add threads API code and Makefile and README
This commit is contained in:
parent
1b24c91885
commit
e5198a301a
|
@ -0,0 +1,23 @@
|
|||
|
||||
FLAGS = -Wall -pthread -g
|
||||
|
||||
all: main-race main-deadlock main-deadlock-global main-signal main-signal-cv
|
||||
|
||||
clean:
|
||||
rm -f main-race main-deadlock main-deadlock-global main-signal main-signal-cv
|
||||
|
||||
main-race: main-race.c common_threads.h
|
||||
gcc -o main-race main-race.c $(FLAGS)
|
||||
|
||||
main-deadlock: main-deadlock.c common_threads.h
|
||||
gcc -o main-deadlock main-deadlock.c $(FLAGS)
|
||||
|
||||
main-deadlock-global: main-deadlock-global.c common_threads.h
|
||||
gcc -o main-deadlock-global main-deadlock-global.c $(FLAGS)
|
||||
|
||||
main-signal: main-signal.c common_threads.h
|
||||
gcc -o main-signal main-signal.c $(FLAGS)
|
||||
|
||||
main-signal-cv: main-signal-cv.c common_threads.h
|
||||
gcc -o main-signal-cv main-signal-cv.c $(FLAGS)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
# Overview
|
||||
|
||||
In this homework, you'll use a real tool on Linux to find problems in
|
||||
multi-threaded code. The tool is called `helgrind` (available as part of the
|
||||
valgrind suite of debugging tools).
|
||||
|
||||
See `http://valgrind.org/docs/manual/hg-manual.htm` for details about
|
||||
the tool, including how to download and install it (if it's not
|
||||
already on your Linux system).
|
||||
|
||||
You'll then look at a number of multi-threaded C programs to see how you can
|
||||
use the tool to debug problematic threaded code.
|
||||
|
||||
First things first: download and install `valgrind` and the related `helgrind` tool.
|
||||
|
||||
Then, type `make` to build all the different programs. Examine the `Makefile`
|
||||
for more details on how that works.
|
||||
|
||||
Then, you have a few different C programs to look at:
|
||||
- `main-race.c`: A simple race condition
|
||||
- `main-deadlock.c`: A simple deadlock
|
||||
- `main-deadlock-global.c`: A solution to the deadlock problem
|
||||
- `main-signal.c`: A simple child/parent signaling example
|
||||
- `main-signal-cv.c`: A more efficient signaling via condition variables
|
||||
- `common_threads.h`: Header file with wrappers to make code check errors and be more readable
|
||||
|
||||
With these programs, you can now answer the questions in the textbook.
|
||||
|
||||
|
||||
|
||||
|
|
@ -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,31 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "common_threads.h"
|
||||
|
||||
pthread_mutex_t g = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void* worker(void* arg) {
|
||||
Pthread_mutex_lock(&g);
|
||||
if ((long long) arg == 0) {
|
||||
Pthread_mutex_lock(&m1);
|
||||
Pthread_mutex_lock(&m2);
|
||||
} else {
|
||||
Pthread_mutex_lock(&m2);
|
||||
Pthread_mutex_lock(&m1);
|
||||
}
|
||||
Pthread_mutex_unlock(&m1);
|
||||
Pthread_mutex_unlock(&m2);
|
||||
Pthread_mutex_unlock(&g);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t p1, p2;
|
||||
Pthread_create(&p1, NULL, worker, (void *) (long long) 0);
|
||||
Pthread_create(&p2, NULL, worker, (void *) (long long) 1);
|
||||
Pthread_join(p1, NULL);
|
||||
Pthread_join(p2, NULL);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "common_threads.h"
|
||||
|
||||
pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void* worker(void* arg) {
|
||||
if ((long long) arg == 0) {
|
||||
Pthread_mutex_lock(&m1);
|
||||
Pthread_mutex_lock(&m2);
|
||||
} else {
|
||||
Pthread_mutex_lock(&m2);
|
||||
Pthread_mutex_lock(&m1);
|
||||
}
|
||||
Pthread_mutex_unlock(&m1);
|
||||
Pthread_mutex_unlock(&m2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t p1, p2;
|
||||
Pthread_create(&p1, NULL, worker, (void *) (long long) 0);
|
||||
Pthread_create(&p2, NULL, worker, (void *) (long long) 1);
|
||||
Pthread_join(p1, NULL);
|
||||
Pthread_join(p2, NULL);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "common_threads.h"
|
||||
|
||||
int balance = 0;
|
||||
|
||||
void* worker(void* arg) {
|
||||
balance++; // unprotected access
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t p;
|
||||
Pthread_create(&p, NULL, worker, NULL);
|
||||
balance++; // unprotected access
|
||||
Pthread_join(p, NULL);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "common_threads.h"
|
||||
|
||||
//
|
||||
// simple synchronizer: allows one thread to wait for another
|
||||
// structure "synchronizer_t" has all the needed data
|
||||
// methods are:
|
||||
// init (called by one thread)
|
||||
// wait (to wait for a thread)
|
||||
// done (to indicate thread is done)
|
||||
//
|
||||
typedef struct __synchronizer_t {
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
int done;
|
||||
} synchronizer_t;
|
||||
|
||||
synchronizer_t s;
|
||||
|
||||
void signal_init(synchronizer_t *s) {
|
||||
Pthread_mutex_init(&s->lock, NULL);
|
||||
Pthread_cond_init(&s->cond, NULL);
|
||||
s->done = 0;
|
||||
}
|
||||
|
||||
void signal_done(synchronizer_t *s) {
|
||||
Pthread_mutex_lock(&s->lock);
|
||||
s->done = 1;
|
||||
Pthread_cond_signal(&s->cond);
|
||||
Pthread_mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
void signal_wait(synchronizer_t *s) {
|
||||
Pthread_mutex_lock(&s->lock);
|
||||
while (s->done == 0)
|
||||
Pthread_cond_wait(&s->cond, &s->lock);
|
||||
Pthread_mutex_unlock(&s->lock);
|
||||
}
|
||||
|
||||
void* worker(void* arg) {
|
||||
printf("this should print first\n");
|
||||
signal_done(&s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t p;
|
||||
signal_init(&s);
|
||||
Pthread_create(&p, NULL, worker, NULL);
|
||||
signal_wait(&s);
|
||||
printf("this should print last\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "common_threads.h"
|
||||
|
||||
int done = 0;
|
||||
|
||||
void* worker(void* arg) {
|
||||
printf("this should print first\n");
|
||||
done = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t p;
|
||||
Pthread_create(&p, NULL, worker, NULL);
|
||||
while (done == 0)
|
||||
;
|
||||
printf("this should print last\n");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue