What will happen if pthread_cond_wait() competes with another thread? - c

Here is a program bellow and its function is counting words in two files with 3 threads(one is the main thread, one for file1, and one for file2).
I know that pthread_cond_wait(&flag, &lock) will lock the mutex before it returns. But what will happen if another thread locks the mutex first?
In this program:
main thread calls pthread_cond_wait, it unlocks the mutex.
thread1 locks the mutex, after doing something, it calls pthread_cond_signal.
main thread got the signal sent by thread1, then it wants to lock the mutex, but the mutex was lock by thread1, so the main thread is blocked.
thread1 unlocks the mutex.
main thread(pthread_cond_wait) now can lock the mutex and return.
But! At this moment(step 5), what will happen if another thread, say thread2, locks the mutex first before pthread_cond_wait locks the mutex? The main thread is still blocked? If it does, then
this program is a buggy program, all the threads(main thread and thread2) will be blocked. But I have run it a lot of times, it worked fine.
Update My Question: Will other threads lock the mutex during the period between the moment that pthread_cond_wait gets the signal sent by pthread_cond_signal requiring the mutex to lock and the moment that pthread_cond_wait locks the mutex.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <ctype.h>
struct arg_set { /* two values int one arg */
char *filename; /* file to examine */
int count; /* number of words */
int code;
};
struct arg_set *mailbox = NULL;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t flag = PTHREAD_COND_INITIALIZER;
void *count_words(void *);
int main(int argc, char *argv[])
{
pthread_t t1, t2; /* two threads */
struct arg_set args1, args2; /* two argsets */
int reports_int = 0;
int total_words = 0;
if (argc != 3) {
fprintf(stderr, "usage: %s file1 file2", argv[0]);
exit(1);
}
pthread_mutex_lock(&lock);
args1.filename = argv[1];
args1.count = 0;
args1.code = 1;
pthread_create(&t1, NULL, count_words, (void *)&args1);
args2.filename = argv[2];
args2.count = 0;
args2.code = 2;
pthread_create(&t2, NULL, count_words, (void *)&args2);
while (reports_int < 2) {
printf("MAIN: waiting for flag to go up\n");
pthread_cond_wait(&flag, &lock);
printf("MAIN: Wow! flag was raised, I have the lock\n");
printf("%7d: %s\n", mailbox->count, mailbox->filename);
total_words += mailbox->count;
if (mailbox == &args1)
pthread_join(t1, NULL);
if (mailbox == &args2)
pthread_join(t2, NULL);
mailbox = NULL;
pthread_cond_signal(&flag);
reports_int++;
}
printf("%7d: total words\n", total_words);
return 0;
}
void *count_words(void *a)
{
struct arg_set *args = a;
FILE *fp;
int c, prevc = '\0';
if ((fp = fopen(args->filename, "r")) != NULL) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
args->count++;
prevc = c;
}
fclose(fp);
} else
perror(args->filename);
printf("COUNT %d: waiting to get lock\n", args->code);
pthread_mutex_lock(&lock);
printf("COUNT %d: have lock, storing data\n", args->code);
if (mailbox != NULL)
pthread_cond_wait(&flag, &lock);
mailbox = args;
printf("COUNT %d: raising flag\n", args->code);
pthread_cond_signal(&flag);
printf("COUNT %d: unlocking box\n", args->code);
pthread_mutex_unlock(&lock);
return NULL;
}

Related

Only three of my five threads are executing, synchronizing using mutexes

I am doing an academic exercise for an OS class where we synchronize five detached threads using ONLY mutex locks and unlocks. We "CANNOT force the threads into any serial execution. Once spawned they must be free from external influences (other than the mutexes). The parent should NOT employ a pthread_join."
I am spawning 5 threads, detaching them and then using each threads to read in data and update a global variable. Currently my code spawns the 5 threads but only three of them output their ID's and none of them get into the while loop. Any help/advice here would be appreciated!
Output:
thread: 6156515168
thread: 6156515192
thread: 6156515176
There is a sleep in main which if uncommented provides the expected output, but this would be forcing a serial execution..
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER; // declaring mutex
int FileNameHelper=1;
int balance=0;
void* detatchedThread(void *param){
long tid = (long)param;
char* base = "data";
char filename[256];
char buf[100];
sprintf(filename, "%s%d.in", base, FileNameHelper); //creates data1.in, data2.in...
FileNameHelper ++;
FILE *inputFile = fopen(filename, "r");
printf ("thread: %ld\n", tid);
// critical sec line
if(fgets(buf, sizeof buf, inputFile) == NULL)
return NULL; // could not read first line
sleep(1); // make sure each thread runs long enough to get the random update behavior required.
pthread_mutex_lock(&mutex_lock); //we are in the critical section, lock mutex
while(fgets(buf, sizeof buf, inputFile) != NULL) {
int val;
if(sscanf(buf, "%d", &val) != 1){
break;
}
printf("%d\n", val);
balance += val;
printf ("Account balance after thread %ld is $%d\n", tid, balance);
}
pthread_mutex_unlock(&mutex_lock);
if(buf[0] != 'W')
return NULL;// last line data was invalid
pthread_exit(NULL);
}
int main(){
pthread_t th[5];
//initialize the mutex
if(pthread_mutex_init(&mutex_lock, NULL) != 0){
printf("\nmutex init has failed\n");
return 1;
}
//call the 5 threads, Detach the threads once they are created.
for (int i = 0; i < 5; i++){
pthread_create(&th[i], NULL, detatchedThread, (void *)&th[i]);
pthread_detach(th[i]);
//sleep(1); uncommenting this line gives me the expected behavior
}
pthread_mutex_destroy(&mutex_lock);
return 0;
}

Can I signal multiple threads simultaneously with pthread_cond_wait(,)?

I am writing various code snippets and see what happens. The code below was intended to delay all threads until all reached a certain point in the code and then make each print a distinctive number. Since the threads all do that, the numbers should occur in a random order.
My current problem is that I keep they threads busy waiting. If the number of threads gets big, the program slows down significantly.
I would like to change that by using signals, I found pthread_cond_wait() for that, however I don't see how one would use that to signal all threads that they would please wake up.
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define threads 10
int counter=0;
pthread_mutex_t lock;
void handler(void *v) {
pthread_mutex_lock(&lock);
counter++;
printf("%d\n", counter);
pthread_mutex_unlock(&lock);
while(counter != threads); // busy waiting
printf("I am first! %d\n", v);
}
int main() {
pthread_t t[threads];
for(int i =0; i < threads; i++) {
pthread_create(&t[i], NULL, handler, (void*) i);
}
for(int i =0; i < threads; i++) {
pthread_join(t[i], NULL);
}
return 0;
}
EDIT: I changed the code to the following, however, it still does not work :/
pthread_mutex_t lock;
pthread_cond_t cv;
void handler(void *v) {
pthread_mutex_lock(&lock);
pthread_cond_wait(&cv, &lock);
printf("I am first! %d\n", v);
pthread_mutex_unlock(&lock);
}
int main() {
pthread_t t[threads];
for(int i =0; i < threads; i++)
pthread_create(&t[i], NULL, handler, (void*) i);
sleep(2);
pthread_cond_signal(&cv);
for(int i =0; i < threads; i++)
pthread_join(t[i], NULL);
return 0;
}
use broadcast()?
http://pubs.opengroup.org/onlinepubs/009696699/functions/pthread_cond_broadcast.html
The pthread_cond_broadcast() function shall unblock all threads currently blocked on the specified condition variable cond.
The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).
An alternative solution to pthread_cond_broadcast() might be the following.
You define a read-write mutex and lock it in write in the main thread before creating the other threads. The other threads will try to acquire a read-lock but since the main thread have a write-lock they will be blocked.
After the creation of all thread the main-thread releases the lock. All the other threads will be waken up and since many read-locks can coexist the will execute simultaneously (i.e. no one will be locked).
Code might be something like:
pthread_rwlock_t lock;
void handler(void *v) {
if ((res = pthread_rwlock_rdlock(&lock)!=0)
{
exit(1);
}
printf("I am first! %d\n", v);
pthread_rwlock_unlock(&lock);
}
int main() {
pthread_t t[threads];
//First acquire the write lock:
if ((res = pthread_rwlock_wrlock(&lock)!=0)
{
exit(1);
}
for(int i =0; i < threads; i++)
{
pthread_create(&t[i], NULL, handler, (void*) i);
//it is not clear if you want sleep inside the loop or not
// You indented it as if to be inside but not put brackets
sleep(2);
}
pthread_rwlock_unlock(&lock);
for(int i =0; i < threads; i++)
pthread_join(t[i], NULL);
pthread_rwlock_destroy(&lock);
return 0;
}
Try posting the matching remove_from_buffer code.
Better yet, Short, Self Contained, Correct Example
Make a short main() with two threads.
One thread adds to the buffer at random intervals.
The other thread removes from the buffer at random intervals.
Example
CELEBP22
/* CELEBP22 */
#define _OPEN_THREADS
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
int footprint = 0;
void *thread(void *arg) {
time_t T;
if (pthread_mutex_lock(&mutex) != 0) {
perror("pthread_mutex_lock() error");
exit(6);
}
time(&T);
printf("starting wait at %s", ctime(&T));
footprint++;
if (pthread_cond_wait(&cond, &mutex) != 0) {
perror("pthread_cond_timedwait() error");
exit(7);
}
time(&T);
printf("wait over at %s", ctime(&T));
}
main() {
pthread_t thid;
time_t T;
struct timespec t;
if (pthread_mutex_init(&mutex, NULL) != 0) {
perror("pthread_mutex_init() error");
exit(1);
}
if (pthread_cond_init(&cond, NULL) != 0) {
perror("pthread_cond_init() error");
exit(2);
}
if (pthread_create(&thid, NULL, thread, NULL) != 0) {
perror("pthread_create() error");
exit(3);
}
while (footprint == 0)
sleep(1);
puts("IPT is about ready to release the thread");
sleep(2);
if (pthread_cond_signal(&cond) != 0) {
perror("pthread_cond_signal() error");
exit(4);
}
if (pthread_join(thid, NULL) != 0) {
perror("pthread_join() error");
exit(5);
}
}
OUTPUT
starting wait at Fri Jun 16 10:54:06 2006 IPT is about ready to
release the thread wait over at Fri Jun 16 10:54:09 2006

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 Threads - Sync

I have this code, I am trying to create n threads, Do some work in each thread, and then reap each thread. If n thread is even, use detach, and if odd, use join,
When i run the program, it first prints out Successfully reaped thread, then doing working, then successfully reaped thread... looks like i have some synchronization issues
Do I even need to use Mutex?
Can anyone help me with getting everything running in the right order?
Thank you
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t lock;
void *dowork(){
//Do whatever needs to be done in each thread here
pthread_mutex_lock(&lock);
long tid = (long) pthread_self();
printf("Doing Work ...for %ld\n",tid);
pthread_mutex_unlock(&lock);
//pthread_exit(NULL);
return;
}
void spawn(int n){
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
exit (1);
}
int i=0;
//pthread_t * thread = malloc(sizeof(pthread_t)*n);
pthread_t threads[n];
while (i<n) {
if(pthread_create(&(threads[i]), NULL, dowork, NULL) != 0){
printf ("Create pthread error!\n");
exit (1);
}
i++;
}//End of while
// Wait for threads to complete //
i = 0;
while (i<n)
{
int success = -1;
if(i%2 == 0){
success=pthread_detach(threads[i]);
}
else{
success=pthread_join(threads[i], NULL);
}
if(success==0)
printf("Succesfully reaped thread\n");
i++;
}
pthread_mutex_destroy(&lock);
}
int main() {
spawn(5);
}

pthread_join blocks my code

can you explain me why the following use of pthread_join doesn't work?it blocks my code.
if I comment those 3 lines, my code does what is expected, but obviously I don't know if threads are terminated(in my code there is no problem for that, but in a bigger situation there is).
int k=0;
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
struct primi{
int s;
int temp;
};
struct example{
int c;
struct primi primissimi;
};
void *funzione_thread(void* args);
void prepare(void){
printf("preparing locks...\n");
pthread_mutex_lock(&mutex); }
void parent(void){
printf("parent unlocking locks...\n");
pthread_mutex_unlock(&mutex);}
void child(void){
printf("child unlocking locks...\n");
pthread_mutex_unlock(&mutex); }
void *thr_fn(void *arg){
printf("thread started...\n");
return(0);}
void *funzione_thread(void* args){
pthread_mutex_lock(&mutex);
struct example *exthread = args;
struct example locale = *exthread;
locale.primissimi.s++;pthread_mutex_unlock(&mutex);
printf("local is %d original is %d\n",locale.primissimi.s,exthread->primissimi.s);
exthread->primissimi.s = locale.primissimi.s;
printf("after it is%d\n",exthread->primissimi.s);
pthread_exit(NULL);
}
int ffork(struct example *extmp){
pthread_t id[5];
int i;
while(k<3){
k++;
pthread_create(&id[k],NULL,funzione_thread,extmp);
}
printf("now k is %d\n\n",k);
for(i=1;i<=3;i++){
pthread_join( id[i] ,NULL );
printf("waited thread %d\n",i);
}
printf("threads completed\n");
pthread_exit (NULL);
//return 1;
}
int main(int argc, char** argv){
struct example *ex = malloc(sizeof(*ex));
int pid,tmp;
pthread_t tid;
if ((err = pthread_atfork(prepare, parent, child)) != 0){
printf("can't install fork handlers");
exit(-1);}
pthread_create(&tid, NULL, thr_fn, 0);
sleep(1);
pid=fork();
if(pid==0){
ex->c=1;
ex->primissimi.s=1;
if((tmp=ffork(ex))!=1){
printf("errore in ffork\n");
sleep(2);
exit(0);
}
else{printf("tutto ok in ffork\n");
sleep(2);
exit(0);
}
}//fine figlio
else{
sleep(10);
}
return 0;
}
Your code has no protection against calling fork with the mutex locked. Since the thread that locked the mutex doesn't exist in the child, it cannot unlock the mutex ... ever. Any thread in the child that tries to acquire the mutex will deadlock, waiting for the non-existent thread to release the lock.
There are a lot of possible fixes, but the simplest is probably to hold the mutex across the call to fork. You can use an atfork handler to do this. Arrange the handler to acquire the mutex before the fork and release it after (in both the parent and child).
You really need to know what you're doing to use fork together with pthreads, unless you're going to immediately exec in the child.

Resources