Add code needed for semaphore chapter

This commit is contained in:
Remzi Arpaci-Dusseau 2020-06-28 06:05:17 -05:00
parent b80f8dd3be
commit 01965d58b1
8 changed files with 399 additions and 0 deletions

24
threads-sema/README.md Normal file
View File

@ -0,0 +1,24 @@
# Overview
Included in this directory are a number of skeletal code fragments, which you
can fill out to solve various synchronization problems.
And see Allen Downey's book, "A Little Book of Semaphores", for even more
fun. It's also free!
To compile any one of them (say, one called `foo.c`):
```sh
prompt> gcc -o foo foo.c -Wall -pthread
```
And then, to run it:
```sh
prompt> ./foo
```
(maybe with some optional arguments)

72
threads-sema/barrier.c Normal file
View File

@ -0,0 +1,72 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common_threads.h"
// If done correctly, each child should print their "before" message
// before either prints their "after" message. Test by adding sleep(1)
// calls in various locations.
// You likely need two semaphores to do this correctly, and some
// other integers to track things.
typedef struct __barrier_t {
// add semaphores and other information here
} barrier_t;
// the single barrier we are using for this program
barrier_t b;
void barrier_init(barrier_t *b, int num_threads) {
// initialization code goes here
}
void barrier(barrier_t *b) {
// barrier code goes here
}
//
// XXX: don't change below here (just run it!)
//
typedef struct __tinfo_t {
int thread_id;
} tinfo_t;
void *child(void *arg) {
tinfo_t *t = (tinfo_t *) arg;
printf("child %d: before\n", t->thread_id);
barrier(&b);
printf("child %d: after\n", t->thread_id);
return NULL;
}
// run with a single argument indicating the number of
// threads you wish to create (1 or more)
int main(int argc, char *argv[]) {
assert(argc == 2);
int num_threads = atoi(argv[1]);
assert(num_threads > 0);
pthread_t p[num_threads];
tinfo_t t[num_threads];
printf("parent: begin\n");
barrier_init(&b, num_threads);
int i;
for (i = 0; i < num_threads; i++) {
t[i].thread_id = i;
Pthread_create(&p[i], NULL, child, &t[i]);
}
for (i = 0; i < num_threads; i++)
Pthread_join(p[i], NULL);
printf("parent: end\n");
return 0;
}

View File

@ -0,0 +1,37 @@
#ifndef __common_threads_h__
#define __common_threads_h__
#include <pthread.h>
#include <assert.h>
#include <sched.h>
#ifdef __linux__
#include <semaphore.h>
#endif
#define Pthread_create(thread, attr, start_routine, arg) assert(pthread_create(thread, attr, start_routine, arg) == 0);
#define Pthread_join(thread, value_ptr) assert(pthread_join(thread, value_ptr) == 0);
#define Pthread_mutex_init(m, v) assert(pthread_mutex_init(m, v) == 0);
#define Pthread_mutex_lock(m) assert(pthread_mutex_lock(m) == 0);
#define Pthread_mutex_unlock(m) assert(pthread_mutex_unlock(m) == 0);
#define Pthread_cond_init(cond, v) assert(pthread_cond_init(cond, v) == 0);
#define Pthread_cond_signal(cond) assert(pthread_cond_signal(cond) == 0);
#define Pthread_cond_wait(cond, mutex) assert(pthread_cond_wait(cond, mutex) == 0);
#define Mutex_init(m) assert(pthread_mutex_init(m, NULL) == 0);
#define Mutex_lock(m) assert(pthread_mutex_lock(m) == 0);
#define Mutex_unlock(m) assert(pthread_mutex_unlock(m) == 0);
#define Cond_init(cond) assert(pthread_cond_init(cond, NULL) == 0);
#define Cond_signal(cond) assert(pthread_cond_signal(cond) == 0);
#define Cond_wait(cond, mutex) assert(pthread_cond_wait(cond, mutex) == 0);
#ifdef __linux__
#define Sem_init(sem, value) assert(sem_init(sem, 0, value) == 0);
#define Sem_wait(sem) assert(sem_wait(sem) == 0);
#define Sem_post(sem) assert(sem_post(sem) == 0);
#endif // __linux__
#endif // __common_threads_h__

23
threads-sema/fork-join.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "common_threads.h"
sem_t s;
void *child(void *arg) {
printf("child\n");
// use semaphore here
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t p;
printf("parent: begin\n");
// init semaphore here
Pthread_create(&p, NULL, child, NULL);
// use semaphore here
printf("parent: end\n");
return 0;
}

View File

@ -0,0 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "common_threads.h"
//
// Here, you have to write (almost) ALL the code. Oh no!
// How can you show that a thread does not starve
// when attempting to acquire this mutex you build?
//
typedef __ns_mutex_t {
} ns_mutex_t;
void ns_mutex_init(ns_mutex_t *m) {
}
void ns_mutex_acquire(ns_mutex_t *m) {
}
void ns_mutex_release(ns_mutex_t *m) {
}
void *worker(void *arg) {
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
printf("parent: end\n");
return 0;
}

View File

@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common_threads.h"
//
// Your code goes in the structure and functions below
//
typedef struct __rwlock_t {
} rwlock_t;
void rwlock_init(rwlock_t *rw) {
}
void rwlock_acquire_readlock(rwlock_t *rw) {
}
void rwlock_release_readlock(rwlock_t *rw) {
}
void rwlock_acquire_writelock(rwlock_t *rw) {
}
void rwlock_release_writelock(rwlock_t *rw) {
}
//
// Don't change the code below (just use it!)
//
int loops;
int value = 0;
rwlock_t lock;
void *reader(void *arg) {
int i;
for (i = 0; i < loops; i++) {
rwlock_acquire_readlock(&lock);
printf("read %d\n", value);
rwlock_release_readlock(&lock);
}
return NULL;
}
void *writer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
rwlock_acquire_writelock(&lock);
value++;
printf("write %d\n", value);
rwlock_release_writelock(&lock);
}
return NULL;
}
int main(int argc, char *argv[]) {
assert(argc == 4);
int num_readers = atoi(argv[1]);
int num_writers = atoi(argv[2]);
loops = atoi(argv[3]);
pthread_t pr[num_readers], pw[num_writers];
rwlock_init(&lock);
printf("begin\n");
int i;
for (i = 0; i < num_readers; i++)
Pthread_create(&pr[i], NULL, reader, NULL);
for (i = 0; i < num_writers; i++)
Pthread_create(&pw[i], NULL, writer, NULL);
for (i = 0; i < num_readers; i++)
Pthread_join(pr[i], NULL);
for (i = 0; i < num_writers; i++)
Pthread_join(pw[i], NULL);
printf("end: value %d\n", value);
return 0;
}

View File

@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common_threads.h"
//
// Your code goes in the structure and functions below
//
typedef struct __rwlock_t {
} rwlock_t;
void rwlock_init(rwlock_t *rw) {
}
void rwlock_acquire_readlock(rwlock_t *rw) {
}
void rwlock_release_readlock(rwlock_t *rw) {
}
void rwlock_acquire_writelock(rwlock_t *rw) {
}
void rwlock_release_writelock(rwlock_t *rw) {
}
//
// Don't change the code below (just use it!)
//
int loops;
int value = 0;
rwlock_t lock;
void *reader(void *arg) {
int i;
for (i = 0; i < loops; i++) {
rwlock_acquire_readlock(&lock);
printf("read %d\n", value);
rwlock_release_readlock(&lock);
}
return NULL;
}
void *writer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
rwlock_acquire_writelock(&lock);
value++;
printf("write %d\n", value);
rwlock_release_writelock(&lock);
}
return NULL;
}
int main(int argc, char *argv[]) {
assert(argc == 4);
int num_readers = atoi(argv[1]);
int num_writers = atoi(argv[2]);
loops = atoi(argv[3]);
pthread_t pr[num_readers], pw[num_writers];
rwlock_init(&lock);
printf("begin\n");
int i;
for (i = 0; i < num_readers; i++)
Pthread_create(&pr[i], NULL, reader, NULL);
for (i = 0; i < num_writers; i++)
Pthread_create(&pw[i], NULL, writer, NULL);
for (i = 0; i < num_readers; i++)
Pthread_join(pr[i], NULL);
for (i = 0; i < num_writers; i++)
Pthread_join(pw[i], NULL);
printf("end: value %d\n", value);
return 0;
}

36
threads-sema/rendezvous.c Normal file
View File

@ -0,0 +1,36 @@
#include <stdio.h>
#include <unistd.h>
#include "common_threads.h"
// If done correctly, each child should print their "before" message
// before either prints their "after" message. Test by adding sleep(1)
// calls in various locations.
sem_t s1, s2;
void *child_1(void *arg) {
printf("child 1: before\n");
// what goes here?
printf("child 1: after\n");
return NULL;
}
void *child_2(void *arg) {
printf("child 2: before\n");
// what goes here?
printf("child 2: after\n");
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t p1, p2;
printf("parent: begin\n");
// init semaphores here
Pthread_create(&p1, NULL, child_1, NULL);
Pthread_create(&p2, NULL, child_2, NULL);
Pthread_join(p1, NULL);
Pthread_join(p2, NULL);
printf("parent: end\n");
return 0;
}