How to implement the pseudocode in the book of semaphores? - c

Lately i followed a course of Operating Systems that sent me to the barrier pseudocode from the little book of semaphores. But for a few hours now i'm struggling to implement this barrier, i can't seem to understand it properly. To understand it, i tried a simple program that lets threads come to barrier, and when all threads arrived, let them pass.
Here's my code:
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#define NR_MAX 5
int n=NR_MAX;
int entered = 0;
pthread_mutex_t mtx;
sem_t smph;
void* bariera(void *v){
pthread_mutex_lock(&mtx);
entered++ ;
printf("thread %d have entered\n", entered);
pthread_mutex_unlock(&mtx);
if(entered == n) {
sem_post(&smph); printf("Out %d \n", entered);}
sem_wait(&smph);
sem_post(&smph);
}
int main() {
pthread_t thr[NR_MAX];
pthread_mutex_init(&mtx, NULL);
sem_init(&smph, 0, 1);
for (int i=0; i<NR_MAX; i ){
pthread_create(&thr[i], NULL, bariera, NULL);
}
for(int i=0; i<NR_MAX; i ){
pthread_join(thr[i], NULL);
}
return 0;
}
How should this be actually implemented? Cause for now, it only prints the order they arrive at the barrier and then it only prints the last one that arrived.
EDIT: Totally forgot, here's the pseudocode:
n = the number of threads
count = 0 - keeps track of how many threads arrived at the barrier
mutex = Semaphore (1) - provides exclusive acces to count
barrier = Semaphore (0) - barrier is locked (zero or negative) until all threads arrive; then it should be unlocked(1 or more)
rendezvous
2
3 mutex.wait()
4 count = count + 1
5 mutex.signal ()
6
7 if count == n: barrier.signal ()
8
9 barrier.wait()
10 barrier.signal ()
11
12 critical point
expected output:
Out 5
Out 4
Out 3
Out 2
Out 1
(the order doesn't have to be the same)
Actual output:
Out 5

Three issues:
Incorrectly initialized semaphore.
Accessing entered outside of the critical section.
Misplaced printf.
Missing return.
Missing increment in for loops.
void* bariera(void *v) {
int id = (int)(uintptr_t)v;
printf("[%d] Before barrier.\n", id);
pthread_mutex_lock(&mtx);
if(++entered == n)
sem_post(&smph); // Wake up a thread.
pthread_mutex_unlock(&mtx);
sem_wait(&smph); // Barrier.
sem_post(&smph); // Wake up another thread.
// Do something after the barrier.
printf("[%d] After barrier.\n", id);
return NULL;
}
sem_init(&smph, 0, 0); // Should initially be zero.
for (int i=0; i<NR_MAX; ++i) {
pthread_create(&thr[i], NULL, bariera, (void*)(intptr_t)i);
}
Output:
[0] Before barrier.
[2] Before barrier.
[3] Before barrier.
[4] Before barrier.
[1] Before barrier.
[1] After barrier.
[0] After barrier.
[3] After barrier.
[2] After barrier.
[4] After barrier.
That leaves the barrier semaphore un-reusuable. To fix that because it posts n+1 times. To leave it back in its original state, we need to post only n times.
void* bariera(void *v) {
int id = (int)(uintptr_t)v;
printf("[%d] Before barrier.\n", id);
pthread_mutex_lock(&mtx);
if(++entered == n)
for (int i=n; i--; )
sem_post(&smph); // Wake up every thread.
pthread_mutex_unlock(&mtx);
sem_wait(&smph); // Barrier.
// Do something after the barrier.
printf("[%d] After barrier.\n", id);
return NULL;
}

With C11 atomic types, you actually don't need the separate mutex to protect access to the barrier counter, as demonstrated below. This version also encapsulates the barrier-related variables and operations into a struct and functions, and doesn't require that the last thread to hit the barrier also have to wait on the semaphore.
#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
struct barrier {
int maxcount;
_Atomic int count;
sem_t sem;
};
void barrier_init(struct barrier *b, int count) {
b->maxcount = b->count = count;
sem_init(&b->sem, 0, 0);
}
void barrier_destroy(struct barrier *b) {
sem_destroy(&b->sem);
}
void barrier_wait(struct barrier *b) {
// Atomically subtract a number and return the *old* value
if (atomic_fetch_sub_explicit(&b->count, 1, memory_order_acq_rel) == 1) {
// Wake up all waiting threads as they're all at the barrier now
for (int n = 0; n < b->maxcount - 1; n += 1) {
sem_post(&b->sem);
}
} else {
sem_wait(&b->sem); // Actual barrier; wake for wakeup
}
}
void* wait_func(void *vb) {
struct barrier *b = vb;
printf("Thread 0x%x before barrier.\n", (unsigned)pthread_self());
barrier_wait(b);
printf("Thread 0x%x after barrier.\n", (unsigned)pthread_self());
return NULL;
}
#define NTHREADS 5
int main(void) {
pthread_t threads[NTHREADS];
struct barrier b;
barrier_init(&b, NTHREADS);
for (int n = 0; n < NTHREADS; n += 1) {
pthread_create(&threads[n], NULL, wait_func, &b);
}
for (int n = 0; n < NTHREADS; n += 1) {
pthread_join(threads[n], NULL);
}
barrier_destroy(&b);
return 0;
}

Related

Global counters and concurrent threads. How to check counter progress?

I am trying to write a simple program to understand threads. I want each thread to increment a global variable 'counter' to 4 million. Each thread only counts to 2 million. I placed a print statement at the end of each function to see how many iterations and where the global counter is at upon completion of the function. But the global counter in thread1Func is always very high, like 3.8 - 3.9 million, and then in thread2Func the counter is always 4 mil (as expected).
Am I doing this correctly? Is there a reason thread1Func is always printing such a high value for 'counter'? I would imagine it should be somewhere between 2 mil - 4 mil more evenly. Any advice would be greatly appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define MAX 2000000UL
pthread_mutex_t lock;
//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct shared_data
{
int value; /* shared variable to store result*/
};
struct shared_data *counter;
void* thread1Func(void * tid){
uint32_t i = 0;
while(i < MAX){
if(pthread_mutex_trylock(&lock) == 0){
counter->value++;
pthread_mutex_unlock(&lock);
i++;
}
}
printf("I am thread 1. I counted %d times. Global counter = %d\n", i, counter->value);
return NULL;
}
void* thread2Func(void * tid){
uint32_t i = 0;
while(i < MAX){
if(pthread_mutex_trylock(&lock) == 0){
counter->value++;
pthread_mutex_unlock(&lock);
i++;
}
}
printf("I am thread 2. I counted %d times. Global counter = %d\n", i, counter->value);
return NULL;
}
int main() {
counter = (struct shared_data *) malloc(sizeof(struct shared_data));
printf("Initial Counter Value: %d\n", counter->value);
pthread_t thread1;
pthread_t thread2;
pthread_mutex_init(&lock, NULL);
pthread_create(&thread1, NULL, thread1Func, NULL);
pthread_create(&thread2, NULL, thread2Func, NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
printf("Final Counter: %d\n", counter->value);
return 0;
}
the global counter in thread1Func is always very high, like 3.8 - 3.9 million, and then in thread2Func the counter is always 4 mil
That is no surprise. If both threads are working at roughly the same speed, then when the first thread finishes, the second thread should be very nearly finished too. The first thread at that point has added its two million to the global counter, and then second thread already will have added almost two million of its own. You should totally expect the global counter to be almost four million when the first thread finishes.
The only way the first thread could print two million is if the first thread is finished before the second thread has begun to work.
Fun example, good work!
Try changing the thread priorities and see what happens to see different counts (see code below).
Maybe consider adding a semaphore to ping pong the count between the 2 threads so they execute equally and report 3999999 and 4000000 as the final counts.
I am sure you have other ideas too, thanks for posting.
gcc main.c -o main
./main
Initial Counter Value: 0
I am thread 2. I counted 2000000 times. Global counter = 3880728
I am thread 1. I counted 2000000 times. Global counter = 4000000
Final Counter: 4000000
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define MAX 2000000UL
pthread_mutex_t lock;
//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct shared_data
{
int value; /* shared variable to store result*/
};
struct shared_data *counter;
void* thread1Func(void * tid){
uint32_t i = 0;
while(i < MAX){
if(pthread_mutex_trylock(&lock) == 0){
counter->value++;
pthread_mutex_unlock(&lock);
i++;
}
}
printf("I am thread 1. I counted %d times. Global counter = %d\n", i, counter->value);
return NULL;
}
void* thread2Func(void * tid){
uint32_t i = 0;
while(i < MAX){
if(pthread_mutex_trylock(&lock) == 0){
counter->value++;
pthread_mutex_unlock(&lock);
i++;
}
}
printf("I am thread 2. I counted %d times. Global counter = %d\n", i, counter->value);
return NULL;
}
int main() {
counter = (struct shared_data *) malloc(sizeof(struct shared_data));
printf("Initial Counter Value: %d\n", counter->value);
pthread_t thread1;
pthread_t thread2;
pthread_mutex_init(&lock, NULL);
pthread_attr_t attr;
struct sched_param sch_params;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, &sch_params);
sch_params.sched_priority = 99;
//pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, &sch_params);
pthread_create(&thread1, &attr, thread1Func, NULL);
sch_params.sched_priority = 1;
pthread_create(&thread2, &attr, thread2Func, NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
printf("Final Counter: %d\n", counter->value);
return 0;
}

Initialize and Deinitialize only once with multiple threads without mutexes

I have two functions initialize() and deinitialize() and each function should run only once. The structure is something similar to:
int *x;
initialize()
{
x = malloc(sizeof(int) * 10);
}
deinitialize()
{
free(x);
}
How can I ensure that only the first thread calls initialize and only the last thread calls deinitialize.
Can this be achieve without the use of mutex?
UPDATE:
Sorry for the poor information. I am actually modifying a library that contains the functions initialize() and deinitialize(). I need to make these two functions thread-safe. The users might use multiple threads and might call these functions more than once. I cannot assume that the users will call exactly once to initialize and deinitialize functions. I can only assume is that if a thread calls initialize, it will call deinitialize at some point.
The users will be using pthread library to create their different threads.
I don't know what you want to achieve, the most easiest is:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
int *x;
int running;
void initialization(void)
{
x = malloc(sizeof(int) * 10);
puts("First thread init x");
}
void deinitialization(void)
{
free(x);
puts("Last thread reset x");
}
void *handler(void *data)
{
printf("Thread started\n");
while (running) {
do_work();
}
printf("Thread exit\n");
}
int main(void)
{
pthread_t threads[3];
initialization();
for (int i = 0; i < 3; i++)
pthread_create(&threads[i], NULL, &handler, NULL);
sleep(2);
running = 0;
for (int i = 0; i < 3; i++)
pthread_join(threads[i], NULL);
deinitialization();
return 0;
}
Here you can be sure that your have called init() and deinit() only once.
UPDATE
Another variant little bit complicated, but here you also can be sure that init() called only once. Thread with id 0 can be start after 1 in this case we should wait while *x is NULL.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX_THREADS 3
int *x;
int running;
int init;
struct thread_info
{
pthread_t thread;
int id;
int first_id;
int last_id;
};
void initialization(void)
{
x = malloc(sizeof(int) * 10);
puts("First thread init x");
init = 1;
}
void deinitialization(void)
{
free(x);
puts("Last thread reset x");
}
void *handler(void *data)
{
struct thread_info *tinfo = data;
printf("Thread started\n");
if (tinfo->id == 0)
initialization();
while (!init);
/* EMPTY BODY */
while (running) {
do_work();
}
printf("Thread exit\n");
}
int main(void)
{
struct thread_info threads[MAX_THREADS] =
{
[0 ... 2].id = -1,
[0 ... 2].first_id = 0,
[0 ... 2].last_id = (MAX_THREADS - 1)
};
for (int i = 0; i < 3; i++)
pthread_create(&threads[i].thread, NULL, &handler,
((threads[i].id = i), &(threads[i])));
sleep(2);
running = 0;
for (int i = 0; i < 3; i++)
pthread_join(threads[i].thread, NULL);
deinitialization();
return 0;
}
deinit() is a little bit tricky because your last thread can be exiting and free(x) while another thread is still running and maybe use it. So I leave it after all threads is exiting.
This is the point about concurrent programming. You can never make any assumptions about the order in which the threads execute.
The exact timing of when tasks in a concurrent system are executed depend on the scheduling, and tasks need not always be executed concurrently. For example, given two tasks, T1 and T2:
T1 may be executed and finished before T2 or vice versa (serial and
sequential)
T1 and T2 may be executed alternately (serial and concurrent)
T1 and T2 may be executed simultaneously at the same instant of time
(parallel and concurrent)

pthread_cond_wait and pthread_mutex_lock priority?

I have a multiple read threads and one write thread. If I lock mutex on one of the read threads and send broadcast from it, is it guaranteed that mutex will be locked by write thread waiting on pthread_cond_wait() or is there a possibility that another read thread that is wainting on pthread_mutex_lock() will lock mutex? Main question is does pthread_cond_wait() have priority over pthread_mutex_lock()?
If not, how can I achieve that the mutex will always be locked by write thread on pthread_cond_broadcast()?
Example
Read thread:
pthread_mutex_lock(mutex);
pthread_cond_broadcast(cond);
pthread_mutex_unlock(mutex);
Write thread:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
Let's assume both threads, read and write, reach the pthread_mutex_lock in the same moment. So, either write thread acquire the mutex on pthread_mutex_lock call, or read thread.
If it would be the write thread, the read one will wait on pthread_mutex_lock. The write, by calling pthread_cond_wait releases mutex and blocks on cond. It is done atomically. So, when read thread is grantex the mutex, we can be sure the the read one waits on cond. So, broadcast on cond reaches the write thread, it no more waits on cond but - still in scope of pthread_cond_wait - tries to get a lock on mutex (hold be read thread). After broadcasting cond the read thread releases the mutex and it goes to write thread. So write thread finally exits from pthread_cond_wait having the mutex locked. Remember to unlock it later.
If it would be the read thread, the write one will wait on pthread_mutex_lock, the read will broadcast a signal on cond then release the mutex. After then the write thread acquires the mutex on pthread_mutex_lock and immediately releases in it pthread_cond_wait waiting for cond (please note, that previous cond broadcast has no effect on current pthread_cond_wait). In the next iteration of read thread it acquires lock onmutex, send broadcast on cond and unlock mutex. It means the write thread moves forward on cond and acquires lock on mutex.
Does it answer your question about priority?
Update after comment.
Let's assume we have one thread (let's name it A for future reference) holding the lock on mutex and few other trying to acquire the same lock. As soon as the lock is released by first thread, there is no predictable which thread would acquire lock. Moreover, if the A thread has a loop and tries to reacquire lock on mutex, there is a chance it would be granted this lock and other threads would keep waiting. Adding pthread_cond_wait doesn't change anything in scope of granting a lock.
Let me quote fragments of POSIX specification (see https://stackoverflow.com/a/9625267/2989411 for reference):
These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.
And this is only guarantee given by standard regarding order of operations. Order of granting the lock to other threads is rather unpredictable and it changes depending on some very subtle fluctuation in timing.
For only mutex related code, please play a little with following code:
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *th(void *arg) {
int i;
char *s = arg;
for (i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
printf("%s %d\n", s, i);
//sleep(1);
pthread_mutex_unlock(&mutex);
#if 0
pthread_yield();
#endif
}
return NULL;
}
int main() {
int i;
for (i = 0; i < 10; ++i) {
pthread_t t1, t2, t3;
printf("================================\n");
pthread_create(&t1, NULL, th, "t1");
pthread_create(&t2, NULL, th, " t2");
pthread_create(&t3, NULL, th, " t3");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
}
return 0;
}
On one machine (single CPU) it always shows whole loop from t3, then t2 and finally from t1. On another (2 cores) the order of threads is more random, but almost always it shows whole loop for each thread before granting the mutex to other thread. Rarely there is a situation like:
t1 8
t1 9
t3 0
t2 0
t2 1
[removed other t2 output]
t2 8
t2 9
t3 1
t3 2
Enable pthread_yield by replacing #if 0 with #if 1 and watch results and check output. For me it works in a way two threads display their output interlaced, then third thread finally has a chance to work. Add another or more thread. Play with sleep, etc. It confirms the random behaviour.
If you wish to experiment a little, compile and run following piece of code. It's an example of single producer - multiple consumers model. It can be run with two parameters: first is the number of consumer threads, second is the length of produced data series. If no parameters are given there is one consumer thread and 120 items to be processed. I also recommend with sleep/usleep in places marked /* play here */: change the value of arguments, remove the sleep at all, move it - when appropriate - to critical section or replace with pthread_yield and observe changes in behaviour.
#define _GNU_SOURCE
#include <assert.h>
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct data_t {
int seq;
int payload;
struct data_t *next;
};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct data_t *first = NULL, *last = NULL;
int in_progress = 1;
int num_data = 120;
void push(int seq, int payload) {
struct data_t *e;
e = malloc(sizeof(struct data_t));
e->seq = seq;
e->payload = payload;
e->next = NULL;
if (last == NULL) {
assert(first == NULL);
first = last = e;
} else {
last->next = e;
last = e;
}
}
struct data_t pop() {
struct data_t res = {0};
if (first == NULL) {
res.seq = -1;
} else {
res.seq = first->seq;
res.payload = first->payload;
first = first->next;
if (first == NULL) {
last = NULL;
}
}
return res;
}
void *producer(void *arg __attribute__((unused))) {
int i;
printf("producer created\n");
for (i = 0; i < num_data; ++i) {
int val;
sleep(1); /* play here */
pthread_mutex_lock(&mutex);
val = rand() / (INT_MAX / 1000);
push(i, val);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
printf("prod %3d %3d signaled\n", i, val);
}
in_progress = 0;
printf("prod end\n");
pthread_cond_broadcast(&cond);
printf("prod end signaled\n");
return NULL;
}
void *consumer(void *arg) {
char c_id[1024];
int t_id = *(int *)arg;
sprintf(c_id, "%*s c %02d", t_id % 10, "", t_id);
printf("%s created\n", c_id);
while (1) {
struct data_t item;
pthread_mutex_lock(&mutex);
item = pop();
while (item.seq == -1 && in_progress) {
printf("%s waits for data\n", c_id);
pthread_cond_wait(&cond, &mutex);
printf("%s got signal\n", c_id);
item = pop();
}
if (!in_progress && item.seq == -1) {
printf("%s detected end of data.\n", c_id);
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
printf("%s processing %3d %3d\n", c_id, item.seq, item.payload);
sleep(item.payload % 10); /* play here */
printf("%s processed %3d %3d\n", c_id, item.seq, item.payload);
}
printf("%s end\n", c_id);
return NULL;
}
int main(int argc, char *argv[]) {
int num_cons = 1;
pthread_t t_prod;
pthread_t *t_cons;
int i;
int *nums;
if (argc > 1) {
num_cons = atoi(argv[1]);
if (num_cons == 0) {
num_cons = 1;
}
if (num_cons > 99) {
num_cons = 99;
}
}
if (argc > 2) {
num_data = atoi(argv[2]);
if (num_data < 10) {
num_data = 10;
}
if (num_data > 600) {
num_data = 600;
}
}
printf("Spawning %d consumer%s for %d items.\n", num_cons, num_cons == 1 ? "" : "s", num_data);
t_cons = malloc(sizeof(pthread_t) * num_cons);
nums = malloc(sizeof(int) * num_cons);
if (!t_cons || !nums) {
printf("Out of memory!\n");
exit(1);
}
srand(time(NULL));
pthread_create(&t_prod, NULL, producer, NULL);
for (i = 0; i < num_cons; ++i) {
nums[i] = i + 1;
usleep(100000); /* play here */
pthread_create(t_cons + i, NULL, consumer, nums + i);
}
pthread_join(t_prod, NULL);
for (i = 0; i < num_cons; ++i) {
pthread_join(t_cons[i], NULL);
}
free(nums);
free(t_cons);
return 0;
}
I hope I have cleared your doubts and gave you some code to experiment and gain some confidence about pthread behaviour.

C - synchronizing multiple threads w/ mutexs

I'm trying to synchronize multiple (7) threads. I thought I understood how they work until I was trying it on my code and my threads were still printing out of order. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
void *text(void *arg);
long code[] = {4,6,3,1,5,0,2}; //Order in which to start threads
int num = 0;
pthread_mutex_t lock; //Mutex variable
int main()
{
int i;
pthread_t tid[7];
//Check if mutex worked
if (pthread_mutex_init(&lock, NULL) != 0){
printf("Mutex init failed\n");
return 1;
}
//Initialize random number generator
time_t seconds;
time(&seconds);
srand((unsigned int) seconds);
//Create our threads
for (i=0; i<7; i++)
pthread_create(&tid[i], NULL, text, (void*)code[i]);
//Wait for threads to finish
for (i=0; i<7; i++){
if(pthread_join(tid[i], NULL)){
printf("A thread failed to join\n");
}
}
//Destroy mutex
pthread_mutex_destroy(&lock);
//Exit main
return 0;
}
void *text (void *arg)
{
//pthread_mutex_lock(&lock); //lock
long n = (long) arg;
int rand_sec = rand() % (3 - 1 + 1) + 1; //Random num seconds to sleep
while (num != n) {} //Busy wait used to wait for our turn
num++; //Let next thread go
sleep(rand_sec); //Sleep for random amount of time
pthread_mutex_lock(&lock); //lock
printf("This is thread %d.\n", n);
pthread_mutex_unlock(&lock); //unlock
//Exit thread
pthread_exit(0);
}
So here I am trying to make threads 0-6 print IN ORDER but right now they are still scrambled. The commented out mutex lock is where I originally had it, but then moved it down to the line above the print statement but I'm having similar results. I am not sure where the error in my mutex's are, could someone give a hint or point me in the right direction? I really appreciate it. Thanks in advance!
You cannot make threads to run in order with only a mutex because they go in execution in an unpredictable order.
In my approach I use a condition variable and a shared integer variable to create a queueing system. Each thread takes a number and when the current_n number is equal to the one of the actual thread, it enters the critical section and prints its number.
#include <pthread.h>
#include <stdio.h>
#define N_THREAD 7
int current_n = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t number = PTHREAD_COND_INITIALIZER;
void *text (void *arg) {
int i = (int)arg;
pthread_mutex_lock(&mutex);
while ( i > current_n ) {
pthread_cond_wait(&number, &mutex);
}
//i = current_n at this point
/*I use stderr because is not buffered and the output will be printed immediately.
Alternatively you can use printf and then fflush(stdout).
*/
fprintf(stderr, "I'm thread n=%d\n", i);
current_n ++;
pthread_cond_broadcast(&number);
pthread_mutex_unlock(&mutex);
return (void*)0;
}
int main() {
pthread_t tid[N_THREAD];
int i = 0;
for(i = 0; i < N_THREAD; i++) {
pthread_create(&tid[i], NULL, text, (void *)i);
}
for(i = 0; i < N_THREAD; i++) {
if(pthread_join(tid[i], NULL)) {
fprintf(stderr, "A thread failed to join\n");
}
}
return 0;
}
The output is:
I'm thread n=0
I'm thread n=1
I'm thread n=2
I'm thread n=3
I'm thread n=4
I'm thread n=5
I'm thread n=6
Compile with
gcc -Wall -Wextra -O2 test.c -o test -lpthread
Don't worry about the warnings.

Semaphores and Deadlocks in C

I'm trying to code the producer/consumer problem using semaphores. I have 3, 1 acting as a mutex, and another 2 for the buffer which the producers and consumers can add/remove from. When adding/removing from the buffer I use the binary semaphore to lock/unlock it so that the global variables aren't subject to any race conditions. The produce semaphore represents how many spots are available in the buffer (how many things can be put into the buffer) while the consumer semaphore represents how many things can be removed from the buffer. I think my logic is wrong cause I always reach a deadlock. Also when I removed the produce and consume semaphores just to test whether or not the program does what its supposed to do, I still get race conditions even though the binary semaphore should be blocking that. What am I doing wrong?
enter code here
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
#include </usr/include/semaphore.h>
#define MAXITEMS 100
#define PRODUCER_NO 5
#define NUM_PRODUCED 5
void *producer_function (void);
void *consumer_function (void);
void add_buffer (long i);
long get_buffer ();
long sum_value = 0;
long finished_producers;
long buffer[MAXITEMS];
int size = 0;
int front, rear = 0;
pthread_t producerThread[5];
pthread_t consumerThread;
sem_t mutex, produce, consume;
int main(void)
{
int i = 0;
srand (time(NULL));
sem_init (&mutex, 0, 1);
sem_init (&produce, 0, 100);
sem_init (&consume, 0, 0);
for (i = 0; i < 5; i++)
{
pthread_create (&producerThread[i], NULL, (void *) producer_function, NULL);
}
pthread_create (&consumerThread, NULL, (void *) consumer_function, NULL);
for (i = 0; i < 5; i++)
{
pthread_join (producerThread[i], NULL);
}
pthread_join (consumerThread, NULL);
return(0);
}
void *producer_function(void)
{
long counter = 0;
long producer_sum = 0L;
while (counter < NUM_PRODUCED)
{
sem_wait (&mutex);
sem_wait (&produce);
long rndNum = rand() % 10;
producer_sum += rndNum;
add_buffer (rndNum);
sem_post (&consume);
counter++;
if (counter == NUM_PRODUCED)
{
finished_producers++;
}
sem_post (&mutex);
usleep(1000);
}
printf("--+---+----+----------+---------+---+--+---+------+----\n");
printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
printf("--+---+----+----------+---------+---+--+---+------+----\n");
return(0);
}
void *consumer_function (void)
{
while (1)
{
sem_wait (&mutex);
sem_wait (&consume);
long readnum = get_buffer();
sem_post (&produce);
sum_value += readnum;
sem_post (&mutex);
//printf ("%ld\n", sum_value);
if ((finished_producers == PRODUCER_NO) && (size == 0))
{
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("The sum of the all produced items at the end is: %ld \n", sum_value);
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
break;
}
}
}
void add_buffer(long i){
buffer[rear] = i;
rear = (rear+1) % MAXITEMS;
size++;
}
long get_buffer(){
long v;
v = buffer[front];
front = (front+1) % MAXITEMS;
size--;
return v;
}
user2929779,
I think its essential to not have the mutex locked, when waiting for a consume notification in the consumer, or vice versa a produce notification in the producer. Imagine you're getting blocked because of waiting for a consume notification, and no producer was able to publish such a notification then your consumer keeps the mutex locked and no producer ever gets the chance to produce a new item...
So the order is important here:
1.) First wait for notification from remote side
2.) lock mutex
3.) modify global data
4.) release mutex
5.) notify remote side
Try this instead:
void *producer_function(void)
{
long counter = 0;
long producer_sum = 0L;
while (counter < NUM_PRODUCED)
{
sem_wait (&produce);
sem_wait (&mutex);
long rndNum = rand() % 10;
producer_sum += rndNum;
add_buffer (rndNum);
counter++;
if (counter == NUM_PRODUCED)
{
finished_producers++;
}
sem_post (&mutex);
sem_post (&consume);
usleep(1000);
}
printf("--+---+----+----------+---------+---+--+---+------+----\n");
printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
printf("--+---+----+----------+---------+---+--+---+------+----\n");
return(0);
}
void *consumer_function (void)
{
while (1)
{
sem_wait (&consume);
sem_wait (&mutex);
long readnum = get_buffer();
sum_value += readnum;
if ((finished_producers == PRODUCER_NO) && (size == 0))
{
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("The sum of the all produced items at the end is: %ld \n", sum_value);
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
break;
}
sem_post (&mutex);
sem_post (&produce);
//printf ("%ld\n", sum_value);
}
return(0);
}
P.S. For now ignoring return values of system calls just to show example implementation...
P.S.S. See also pseudo code on wiki http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem#Using_semaphores ...

Resources