Skip to content

Commit 1a8e4d4

Browse files
committed
0 parents  commit 1a8e4d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+6234
-0
lines changed

Diff for: Makefile

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Digital UNIX 4.0 compilation flags:
2+
CFLAGS=-std1 -pthread -g -w1 $(DEBUGFLAGS)
3+
RTFLAGS=-lrt
4+
5+
# Solaris 2.5 compilation flags:
6+
#CFLAGS=-D_POSIX_C_SOURCE=199506 -D_REENTRANT -Xa -lpthread -g $(DEBUGFLAGS)
7+
#RTFLAGS=-lposix4
8+
9+
SOURCES=alarm.c alarm_cond.c alarm_fork.c alarm_mutex.c \
10+
alarm_thread.c atfork.c backoff.c \
11+
barrier_main.c cancel.c cancel_async.c cancel_cleanup\
12+
cancel_disable.c cancel_subcontract.c cond.c cond_attr.c \
13+
crew.c cond_dynamic.c cond_static.c flock.c getlogin.c hello.c \
14+
inertia.c lifecycle.c mutex_attr.c \
15+
mutex_dynamic.c mutex_static.c once.c pipe.c putchar.c \
16+
rwlock_main.c rwlock_try_main.c \
17+
sched_attr.c sched_thread.c semaphore_signal.c \
18+
semaphore_wait.c server.c sigev_thread.c \
19+
sigwait.c susp.c thread.c \
20+
thread_attr.c thread_error.c trylock.c tsd_destructor.c \
21+
tsd_once.c workq_main.c
22+
PROGRAMS=$(SOURCES:.c=)
23+
all: ${PROGRAMS}
24+
alarm_mutex:
25+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ alarm_mutex.c
26+
backoff:
27+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ backoff.c
28+
sched_attr:
29+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ sched_attr.c
30+
sched_thread:
31+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ sched_thread.c
32+
semaphore_signal:
33+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ semaphore_signal.c
34+
semaphore_wait:
35+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ semaphore_wait.c
36+
sigev_thread:
37+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ sigev_thread.c
38+
susp:
39+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ susp.c
40+
rwlock_main: rwlock.c rwlock.h rwlock_main.c
41+
${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_main.c rwlock.c
42+
rwlock_try_main: rwlock.h rwlock.c rwlock_try_main.c
43+
${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_try_main.c rwlock.c
44+
barrier_main: barrier.h barrier.c barrier_main.c
45+
${CC} ${CFLAGS} ${LDFLAGS} -o $@ barrier_main.c barrier.c
46+
workq_main: workq.h workq.c workq_main.c
47+
${CC} ${CFLAGS} ${RTFLAGS} ${LDFLAGS} -o $@ workq_main.c workq.c
48+
clean:
49+
@rm -rf $(PROGRAMS) *.o
50+
recompile: clean all

Diff for: README

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
These are the source files for the programming examples in
2+
"Programming With POSIX(r) Threads". The Makefile is pre-configured
3+
for Digital UNIX, but includes the appropriate definitions to build on
4+
Solaris (uncomment the Solaris lines and comment the Digital UNIX
5+
lines).
6+
7+
Some of these examples have been repaired since the original printing
8+
of the book. Some differ from the examples printed in the latest
9+
printing, as well, because the changes were too large to fit. The
10+
signal-based suspend/resume program, susp.c, has been substantially
11+
revised to correct a number of problems with the original version.
12+
13+
alarm.c Simple synchronous alarm clock
14+
alarm_cond.c Threaded alarm clock using condition variable
15+
alarm_fork.c Alarm clock using fork asychrony
16+
alarm_mutex.c Threaded alarm clock using mutex
17+
alarm_thread.c Alarm clock using thread asynchrony
18+
atfork.c Demonstrate pthread_atfork()
19+
backoff.c Demonstrate mutex hierarchy backoff
20+
barrier.c Implementation of barrier package
21+
barrier_main.c Demonstrate use of barrier package
22+
cancel.c Demonstrate cancellation
23+
cancel_async.c Demonstrate asyncronous cancellation
24+
cancel_cleanup.c Demonstrate cancellation cleanup
25+
cancel_disable.c Demonstrate disabling cancellation
26+
cancel_subcontract.c Demonstrate cancellation of "subcontractors"
27+
cond.c Demonstrate use of condition variables
28+
cond_attr.c Demonstrate condition variable attributes
29+
cond_dynamic.c Demonstrate dynamic init of condition variable
30+
cond_static.c Demonstrate static init of condition variable
31+
crew.c A simple threaded work crew
32+
flock.c Demonstrate use of file locking
33+
getlogin.c Demonstrate reentrant user functions
34+
hello.c Demonstrate thread creation
35+
inertia.c Demonstrate "thread inertia" errors
36+
lifecycle.c Demonstrate "thread lifecycle"
37+
mutex_attr.c Demonstrate mutex attributes
38+
mutex_dynamic.c Demonstrate dynamic initialization of mutex
39+
mutex_static.c Demonstrate static initialization of mutex
40+
once.c Demonstrate use of pthread_once()
41+
pipe.c A simple threaded pipeline
42+
putchar.c Demonstrate thread-safe use of putchar()
43+
rwlock.c Implementation of read/write lock package
44+
rwlock_main.c Demonstrate use of read/write lock package
45+
rwlock_try_main.c Demonstrate use of read/write lock package
46+
sched_attr.c Demonstrate thread scheduling attributes
47+
sched_thread.c Demonstrate use of thread scheduling functions
48+
semaphore_signal.c Demonstrate use of semaphores with signals
49+
semaphore_wait.c Demonstrate use of semaphores
50+
server.c A simple threaded client/server program
51+
sigev_thread.c Demonstrate use of SIGEV_THREAD mechanism
52+
sigwait.c Demonstrate use of sigwait()
53+
susp.c Demonstrate use of pthread_kill()
54+
thread.c Demonstrate simple concurrent I/O
55+
thread_attr.c Demonstrate thread attributes
56+
thread_error.c Demonstrate POSIX thread error mechanism
57+
trylock.c Demonstrate use of pthread_mutex_trylock()
58+
tsd_destructor.c Demonstrate thread-specific data destructors
59+
tsd_once.c Demonstrate thread-specific data key creation
60+
workq.c Implementation of work queue package
61+
workq_main.c Demonstrate use of work queue package
62+
63+
Header files:
64+
65+
barrier.h Definitions for barrier package
66+
errors.h General headers and error macros
67+
rwlock.h Definitions for read/write lock package
68+
workq.h Definitions for work queue package
69+
70+
Programs with arguments or special behavior:
71+
72+
alarm, alarm_fork, The alarm programs will prompt for
73+
alarm_thread, alarm_mutex, commands until terminated by ^D
74+
alarm_cond (EOF). Commands are "<n> <s>" where <s>
75+
(the remainder of the line) is a
76+
message to print after <n> seconds.
77+
atfork [hang] Run with an argument of 0 to omit
78+
atfork handlers -- program will hang.
79+
backoff [backoff [delay]] Run with first argument of 0, will not
80+
back off on mutex collision, and will
81+
usually hang. Second argument can be
82+
specified greater than 0 to yield
83+
(increasing chances of hang on
84+
uniprocessor), or less than 0 to sleep
85+
for a second.
86+
crew string path First argument is a search string,
87+
second is a file path.
88+
flock Threads will prompt alternately for
89+
input.
90+
pipe Prompts for integers to feed to
91+
pipeline; enter "=" to pop a result.
92+
putchar [unsync] Run with argument of 0 to concurrently
93+
call putchar_unlocked from multiple
94+
threads.
95+
server Threads each prompt for input, and
96+
echo it 3 times -- server prevents
97+
output while waiting for input.
98+
sigwait Waits for 5 SIGINT signals (^C)
99+
thread One thread writes to stdout while
100+
another waits for input from
101+
stdin. (Satisfy the read to exit.)
102+
103+
/---[ Dave Butenhof ]-----------------------[ [email protected] ]---\
104+
| Compaq Computer Corporation 110 Spit Brook Rd ZKO2-3/Q18 |
105+
| 603.884.7460, FAX 603.884.0120 Nashua NH 03062-2698 |
106+
\-----------------[ Better Living Through Concurrency ]----------------/

Diff for: alarm.c

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* alarm.c
3+
*
4+
* Simple synchronous alarm program. This is used as a
5+
* reference for progressive examples of asynchronous
6+
* alarm programs.
7+
*/
8+
#include "errors.h"
9+
10+
int main (int argc, char *argv[])
11+
{
12+
int seconds;
13+
char line[128];
14+
char message[64];
15+
16+
while (1) {
17+
printf ("Alarm> ");
18+
if (fgets (line, sizeof (line), stdin) == NULL) exit (0);
19+
if (strlen (line) <= 1) continue;
20+
21+
/*
22+
* Parse input line into seconds (%d) and a message
23+
* (%64[^\n]), consisting of up to 64 characters
24+
* separated from the seconds by whitespace.
25+
*/
26+
if (sscanf (line, "%d %64[^\n]",
27+
&seconds, message) < 2) {
28+
fprintf (stderr, "Bad command\n");
29+
} else {
30+
sleep (seconds);
31+
printf ("(%d) %s\n", seconds, message);
32+
}
33+
}
34+
}

Diff for: alarm_cond.c

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* alarm_cond.c
3+
*
4+
* This is an enhancement to the alarm_mutex.c program, which
5+
* used only a mutex to synchronize access to the shared alarm
6+
* list. This version adds a condition variable. The alarm
7+
* thread waits on this condition variable, with a timeout that
8+
* corresponds to the earliest timer request. If the main thread
9+
* enters an earlier timeout, it signals the condition variable
10+
* so that the alarm thread will wake up and process the earlier
11+
* timeout first, requeueing the later request.
12+
*/
13+
#include <pthread.h>
14+
#include <time.h>
15+
#include "errors.h"
16+
17+
/*
18+
* The "alarm" structure now contains the time_t (time since the
19+
* Epoch, in seconds) for each alarm, so that they can be
20+
* sorted. Storing the requested number of seconds would not be
21+
* enough, since the "alarm thread" cannot tell how long it has
22+
* been on the list.
23+
*/
24+
typedef struct alarm_tag {
25+
struct alarm_tag *link;
26+
int seconds;
27+
time_t time; /* seconds from EPOCH */
28+
char message[64];
29+
} alarm_t;
30+
31+
pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
32+
pthread_cond_t alarm_cond = PTHREAD_COND_INITIALIZER;
33+
alarm_t *alarm_list = NULL;
34+
time_t current_alarm = 0;
35+
36+
/*
37+
* Insert alarm entry on list, in order.
38+
*/
39+
void alarm_insert (alarm_t *alarm)
40+
{
41+
int status;
42+
alarm_t **last, *next;
43+
44+
/*
45+
* LOCKING PROTOCOL:
46+
*
47+
* This routine requires that the caller have locked the
48+
* alarm_mutex!
49+
*/
50+
last = &alarm_list;
51+
next = *last;
52+
while (next != NULL) {
53+
if (next->time >= alarm->time) {
54+
alarm->link = next;
55+
*last = alarm;
56+
break;
57+
}
58+
last = &next->link;
59+
next = next->link;
60+
}
61+
/*
62+
* If we reached the end of the list, insert the new alarm
63+
* there. ("next" is NULL, and "last" points to the link
64+
* field of the last item, or to the list header.)
65+
*/
66+
if (next == NULL) {
67+
*last = alarm;
68+
alarm->link = NULL;
69+
}
70+
#ifdef DEBUG
71+
printf ("[list: ");
72+
for (next = alarm_list; next != NULL; next = next->link)
73+
printf ("%d(%d)[\"%s\"] ", next->time,
74+
next->time - time (NULL), next->message);
75+
printf ("]\n");
76+
#endif
77+
/*
78+
* Wake the alarm thread if it is not busy (that is, if
79+
* current_alarm is 0, signifying that it's waiting for
80+
* work), or if the new alarm comes before the one on
81+
* which the alarm thread is waiting.
82+
*/
83+
if (current_alarm == 0 || alarm->time < current_alarm) {
84+
current_alarm = alarm->time;
85+
status = pthread_cond_signal (&alarm_cond);
86+
if (status != 0)
87+
err_abort (status, "Signal cond");
88+
}
89+
}
90+
91+
/*
92+
* The alarm thread's start routine.
93+
*/
94+
void *alarm_thread (void *arg)
95+
{
96+
alarm_t *alarm;
97+
struct timespec cond_time;
98+
time_t now;
99+
int status, expired;
100+
101+
/*
102+
* Loop forever, processing commands. The alarm thread will
103+
* be disintegrated when the process exits. Lock the mutex
104+
* at the start -- it will be unlocked during condition
105+
* waits, so the main thread can insert alarms.
106+
*/
107+
status = pthread_mutex_lock (&alarm_mutex);
108+
if (status != 0)
109+
err_abort (status, "Lock mutex");
110+
while (1) {
111+
/*
112+
* If the alarm list is empty, wait until an alarm is
113+
* added. Setting current_alarm to 0 informs the insert
114+
* routine that the thread is not busy.
115+
*/
116+
current_alarm = 0;
117+
while (alarm_list == NULL) {
118+
status = pthread_cond_wait (&alarm_cond, &alarm_mutex);
119+
if (status != 0)
120+
err_abort (status, "Wait on cond");
121+
}
122+
alarm = alarm_list;
123+
alarm_list = alarm->link;
124+
now = time (NULL);
125+
expired = 0;
126+
if (alarm->time > now) {
127+
#ifdef DEBUG
128+
printf ("[waiting: %d(%d)\"%s\"]\n", alarm->time,
129+
alarm->time - time (NULL), alarm->message);
130+
#endif
131+
cond_time.tv_sec = alarm->time;
132+
cond_time.tv_nsec = 0;
133+
current_alarm = alarm->time;
134+
while (current_alarm == alarm->time) {
135+
status = pthread_cond_timedwait (
136+
&alarm_cond, &alarm_mutex, &cond_time);
137+
if (status == ETIMEDOUT) {
138+
expired = 1;
139+
break;
140+
}
141+
if (status != 0)
142+
err_abort (status, "Cond timedwait");
143+
}
144+
if (!expired)
145+
alarm_insert (alarm);
146+
} else
147+
expired = 1;
148+
if (expired) {
149+
printf ("(%d) %s\n", alarm->seconds, alarm->message);
150+
free (alarm);
151+
}
152+
}
153+
}
154+
155+
int main (int argc, char *argv[])
156+
{
157+
int status;
158+
char line[128];
159+
alarm_t *alarm;
160+
pthread_t thread;
161+
162+
status = pthread_create (
163+
&thread, NULL, alarm_thread, NULL);
164+
if (status != 0)
165+
err_abort (status, "Create alarm thread");
166+
while (1) {
167+
printf ("Alarm> ");
168+
if (fgets (line, sizeof (line), stdin) == NULL) exit (0);
169+
if (strlen (line) <= 1) continue;
170+
alarm = (alarm_t*)malloc (sizeof (alarm_t));
171+
if (alarm == NULL)
172+
errno_abort ("Allocate alarm");
173+
174+
/*
175+
* Parse input line into seconds (%d) and a message
176+
* (%64[^\n]), consisting of up to 64 characters
177+
* separated from the seconds by whitespace.
178+
*/
179+
if (sscanf (line, "%d %64[^\n]",
180+
&alarm->seconds, alarm->message) < 2) {
181+
fprintf (stderr, "Bad command\n");
182+
free (alarm);
183+
} else {
184+
status = pthread_mutex_lock (&alarm_mutex);
185+
if (status != 0)
186+
err_abort (status, "Lock mutex");
187+
alarm->time = time (NULL) + alarm->seconds;
188+
/*
189+
* Insert the new alarm into the list of alarms,
190+
* sorted by expiration time.
191+
*/
192+
alarm_insert (alarm);
193+
status = pthread_mutex_unlock (&alarm_mutex);
194+
if (status != 0)
195+
err_abort (status, "Unlock mutex");
196+
}
197+
}
198+
}

0 commit comments

Comments
 (0)