Add code needed for semaphore chapter
This commit is contained in:
parent
b80f8dd3be
commit
01965d58b1
|
@ -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)
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue