Skip to content

Commit 9805940

Browse files
author
Margo
committed
Add lecture for 11/17
1 parent 1f4b939 commit 9805940

File tree

6 files changed

+367
-0
lines changed

6 files changed

+367
-0
lines changed

synch1/GNUmakefile

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
PROGRAMS = pingpong pingpong1 pingpong-mutex pingpong-cv
2+
all: $(PROGRAMS)
3+
4+
O ?= 2
5+
include ../common/rules.mk
6+
7+
%.o: %.c $(BUILDSTAMP)
8+
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCFLAGS) $(O) -o $@ -c $<
9+
10+
$(PROGRAMS): %: %.o
11+
$(CC) $(CFLAGS) -pthread $(O) -o $@ $^
12+
13+
14+
check: pingpong
15+
./pingpong | awk -f check.awk
16+
17+
check-cv: pingpong-cv
18+
./pingpong-cv | awk -f check.awk
19+
20+
check-mutex: pingpong-mutex
21+
./pingpong-mutex | awk -f check.awk
22+
23+
clean:
24+
rm -f *.o *.core $(PROGRAMS)
25+
rm -rf $(DEPSDIR) *.dSYM
26+
27+
.PHONY: all clean

synch1/README.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pingpong: Unsynchronized version of pingpong pthread program with two threads
2+
of each type (too easy to get behavior correct unsynchronized with
3+
only one thread of each type.
4+
5+
pingpong-mutex:
6+
Synchronize this using a mutex.
7+
8+
pingpong-cv:
9+
Synchronize this using a mutex and CV.
10+
11+
check.awk -- awk script to detect if your ping pong output is correct.

synch1/check.awk

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
BEGIN {
2+
state = 2
3+
}
4+
{
5+
if ($1 == "ping") {
6+
if (state == 0)
7+
printf("Two pings!\n");
8+
state = 0;
9+
} else if ($1 == "pong") {
10+
if (state == 1)
11+
printf("Two pongs!\n");
12+
state = 1;
13+
}
14+
15+
}

synch1/pingpong-cv.c

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// These examples build on/mimic the multi-process ping pong program from
2+
// lecture 18 and the select video. The challenge this time is to synchronize
3+
// two pthreads who need to alternate printing out pings and pongs to the console.
4+
//
5+
// The main program creates four threads (2 pings and 2 pongs). The threads are
6+
// identical except for the messages they print and whether they print on even
7+
// or odd messages. We add an explicit usleep to trigger the race condition.
8+
9+
#include <errno.h>
10+
#include <pthread.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <unistd.h>
15+
16+
// How many total pings and pongs we'll print
17+
#define TOTAL_MSGS 100
18+
19+
// Structure that we'll use to transmit information
20+
// to the threads.
21+
22+
struct pp_thread_info {
23+
int *msgcount; // Keeps track of total number of messages; shared state
24+
char *msg;
25+
int modval;
26+
pthread_mutex_t *mutex; // Sync access to msgcount
27+
pthread_cond_t *cv; // Condition variable to use with mutex
28+
};
29+
30+
// Unsynchronized version -- pings and pongs will not alternate nicely
31+
32+
// Thread function for both pings and pongs; the arg function will be
33+
// pointer to a struct pp_thread_info and carries all the information
34+
// that the thread needs to process pings and pongs.
35+
36+
void *
37+
pp_thread(void *arg)
38+
{
39+
struct pp_thread_info *infop;
40+
int c;
41+
42+
infop = arg;
43+
while (1) {
44+
pthread_mutex_lock(infop->mutex);
45+
if (*infop->msgcount >= TOTAL_MSGS)
46+
break;
47+
while (*infop->msgcount % 2 == infop->modval)
48+
pthread_cond_wait(infop->cv, infop->mutex);
49+
50+
// When we get here, we know that it's time to
51+
// print our message and that we are holding the
52+
// mutex.
53+
printf("%s\n", infop->msg);
54+
c = *infop->msgcount;
55+
sched_yield();
56+
c = c + 1;
57+
*infop->msgcount = c;
58+
59+
pthread_cond_broadcast(infop->cv);
60+
pthread_mutex_unlock(infop->mutex);
61+
sched_yield();
62+
}
63+
pthread_mutex_unlock(infop->mutex);
64+
return (NULL);
65+
}
66+
67+
int
68+
main(void)
69+
{
70+
pthread_t ping_id1, pong_id1;
71+
pthread_t ping_id2, pong_id2;
72+
pthread_mutex_t mutex;
73+
pthread_cond_t cv;
74+
struct pp_thread_info ping, pong;
75+
int msgcount;
76+
77+
msgcount = 0;
78+
79+
if (pthread_mutex_init(&mutex, NULL) != 0) {
80+
fprintf(stderr, "Mutex init failed: %s\n", strerror(errno));
81+
exit(1);
82+
}
83+
if (pthread_cond_init(&cv, NULL) != 0) {
84+
fprintf(stderr, "CV init failed: %s\n", strerror(errno));
85+
exit(1);
86+
}
87+
88+
ping.msgcount = &msgcount;
89+
ping.msg = "ping";
90+
ping.modval = 0;
91+
ping.mutex = &mutex;
92+
ping.cv = &cv;
93+
94+
pong.msgcount = &msgcount;
95+
pong.msg = "pong";
96+
pong.modval = 1;
97+
pong.mutex = &mutex;
98+
pong.cv = &cv;
99+
100+
// Create the two threads
101+
if ((pthread_create(&ping_id1, NULL, &pp_thread, &ping) != 0) ||
102+
(pthread_create(&pong_id1, NULL, &pp_thread, &pong) != 0) ||
103+
(pthread_create(&ping_id2, NULL, &pp_thread, &ping) != 0) ||
104+
(pthread_create(&pong_id2, NULL, &pp_thread, &pong) != 0)) {
105+
fprintf(stderr, "pingpong: pthread_create failed %s\n", strerror(errno));
106+
exit(1);
107+
}
108+
109+
// Now wait for threads to exit (Probably should check for errors)
110+
pthread_join(ping_id1, NULL);
111+
pthread_join(pong_id1, NULL);
112+
pthread_join(ping_id2, NULL);
113+
pthread_join(pong_id2, NULL);
114+
pthread_mutex_destroy(&mutex);
115+
pthread_cond_destroy(&cv);
116+
117+
printf("Main thread exiting\n");
118+
}
119+

synch1/pingpong-mutex.c

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// These examples build on/mimic the multi-process ping pong program from
2+
// lecture 18 and the select video. The challenge this time is to synchronize
3+
// two pthreads who need to alternate printing out pings and pongs to the console.
4+
//
5+
// The main program creates four threads (2 pings and 2 pongs). The threads are
6+
// identical except for the messages they print and whether they print on even
7+
// or odd messages. We add an explicit usleep to trigger the race condition.
8+
9+
#include <errno.h>
10+
#include <pthread.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <unistd.h>
15+
16+
// How many total pings and pongs we'll print
17+
#define TOTAL_MSGS 100
18+
19+
// Structure that we'll use to transmit information
20+
// to the threads.
21+
22+
struct pp_thread_info {
23+
int *msgcount; // Keeps track of total number of messages; shared state
24+
char *msg;
25+
int modval;
26+
pthread_mutex_t *mutex; // Sync access to msgcount
27+
};
28+
29+
// Unsynchronized version -- pings and pongs will not alternate nicely
30+
31+
// Thread function for both pings and pongs; the arg function will be
32+
// pointer to a struct pp_thread_info and carries all the information
33+
// that the thread needs to process pings and pongs.
34+
35+
void *
36+
pp_thread(void *arg)
37+
{
38+
struct pp_thread_info *infop;
39+
int c;
40+
41+
infop = arg;
42+
while (1) {
43+
pthread_mutex_lock(infop->mutex);
44+
if (*infop->msgcount >= TOTAL_MSGS)
45+
break;
46+
if (*infop->msgcount % 2 == infop->modval) {
47+
printf("%s\n", infop->msg);
48+
c = *infop->msgcount;
49+
sched_yield();
50+
c = c + 1;
51+
*infop->msgcount = c;
52+
}
53+
pthread_mutex_unlock(infop->mutex);
54+
sched_yield();
55+
}
56+
pthread_mutex_unlock(infop->mutex);
57+
return (NULL);
58+
}
59+
60+
int
61+
main(void)
62+
{
63+
pthread_t ping_id1, pong_id1;
64+
pthread_t ping_id2, pong_id2;
65+
pthread_mutex_t mutex;
66+
struct pp_thread_info ping, pong;
67+
int msgcount;
68+
69+
msgcount = 0;
70+
71+
if (pthread_mutex_init(&mutex, NULL) != 0) {
72+
fprintf(stderr, "Mutex init failed: %s\n", strerror(errno));
73+
exit(1);
74+
}
75+
76+
ping.msgcount = &msgcount;
77+
ping.msg = "ping";
78+
ping.modval = 0;
79+
ping.mutex = &mutex;
80+
81+
pong.msgcount = &msgcount;
82+
pong.msg = "pong";
83+
pong.modval = 1;
84+
pong.mutex = &mutex;
85+
86+
// Create the two threads
87+
if ((pthread_create(&ping_id1, NULL, &pp_thread, &ping) != 0) ||
88+
(pthread_create(&pong_id1, NULL, &pp_thread, &pong) != 0) ||
89+
(pthread_create(&ping_id2, NULL, &pp_thread, &ping) != 0) ||
90+
(pthread_create(&pong_id2, NULL, &pp_thread, &pong) != 0)) {
91+
fprintf(stderr, "pingpong: pthread_create failed %s\n", strerror(errno));
92+
exit(1);
93+
}
94+
95+
// Now wait for threads to exit (Probably should check for errors)
96+
pthread_join(ping_id1, NULL);
97+
pthread_join(pong_id1, NULL);
98+
pthread_join(ping_id2, NULL);
99+
pthread_join(pong_id2, NULL);
100+
pthread_mutex_destroy(&mutex);
101+
102+
printf("Main thread exiting\n");
103+
}
104+

synch1/pingpong.c

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// These examples build on/mimic the multi-process ping pong program from
2+
// lecture 18 and the select video. The challenge this time is to synchronize
3+
// two pthreads who need to alternate printing out pings and pongs to the console.
4+
//
5+
// The main program creates four threads (2 pings and 2 pongs). The threads are
6+
// identical except for the messages they print and whether they print on even
7+
// or odd messages. We add an explicit usleep to trigger the race condition.
8+
9+
#include <errno.h>
10+
#include <pthread.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <unistd.h>
15+
16+
// How many total pings and pongs we'll print
17+
#define TOTAL_MSGS 100
18+
19+
// Structure that we'll use to transmit information
20+
// to the threads.
21+
22+
struct pp_thread_info {
23+
int *msgcount; // Keeps track of total number of messages; shared state
24+
char *msg;
25+
int modval;
26+
};
27+
28+
// Unsynchronized version -- pings and pongs will not alternate nicely
29+
30+
// Thread function for both pings and pongs; the arg function will be
31+
// pointer to a struct pp_thread_info and carries all the information
32+
// that the thread needs to process pings and pongs.
33+
34+
void *
35+
pp_thread(void *arg)
36+
{
37+
struct pp_thread_info *infop;
38+
int c;
39+
40+
infop = arg;
41+
while (1) {
42+
if (*infop->msgcount >= TOTAL_MSGS)
43+
break;
44+
if (*infop->msgcount % 2 == infop->modval) {
45+
printf("%s\n", infop->msg);
46+
c = *infop->msgcount;
47+
sched_yield();
48+
c = c + 1;
49+
*infop->msgcount = c;
50+
}
51+
sched_yield();
52+
}
53+
return (NULL);
54+
}
55+
56+
int
57+
main(void)
58+
{
59+
pthread_t ping_id1, pong_id1;
60+
pthread_t ping_id2, pong_id2;
61+
struct pp_thread_info ping, pong;
62+
int msgcount;
63+
64+
msgcount = 0;
65+
66+
ping.msgcount = &msgcount;
67+
ping.msg = "ping";
68+
ping.modval = 0;
69+
70+
pong.msgcount = &msgcount;
71+
pong.msg = "pong";
72+
pong.modval = 1;
73+
74+
// Create the four threads
75+
if ((pthread_create(&ping_id1, NULL, &pp_thread, &ping) != 0) ||
76+
(pthread_create(&pong_id1, NULL, &pp_thread, &pong) != 0) ||
77+
(pthread_create(&ping_id2, NULL, &pp_thread, &ping) != 0) ||
78+
(pthread_create(&pong_id2, NULL, &pp_thread, &pong) != 0)) {
79+
fprintf(stderr, "pingpong: pthread_create failed %s\n", strerror(errno));
80+
exit(1);
81+
}
82+
83+
// Now wait for threads to exit (Probably should check for errors)
84+
pthread_join(ping_id1, NULL);
85+
pthread_join(pong_id1, NULL);
86+
pthread_join(ping_id2, NULL);
87+
pthread_join(pong_id2, NULL);
88+
89+
printf("Main thread exiting\n");
90+
}
91+

0 commit comments

Comments
 (0)