I hope you will be able to help me in my trouble. My program is doing something I don't really understand.
The program purpose is given as below:
Create two threads (task_timer and task_read).
These threads have to display on the standard output (stdout) the following message :
"Tache 1
Tache 2
Tache 1
Tache 2
..."
Code :
static void* task_timer(void* arg);
static void* task_read(void* p);
struct strShared{
pthread_mutex_t mut;
pthread_mutex_t mut2;
pthread_cond_t synchro;
pthread_cond_t synchro2;
};
struct strTimer{
int wt;
strShared* psh;
};
static void* task_timer(void* p){
time_t echeance;
strTimer* timer;
int time_waiting = 1000;
time_t now;
if(p != NULL){
timer = p;
time_waiting = timer->wt; //ms
echeance = time (NULL) + TIME_OF_THREAD;
while (1)
{
pthread_mutex_lock(&timer->psh->mut);
printf("Tache 1\n");
pthread_cond_signal(&timer->psh->synchro);
pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut);
pthread_mutex_unlock(&timer->psh->mut);
}
}
return NULL;
}
static void* task_read(void* p){
strTimer* timer;
if(p != NULL){
timer = p;
while(1){
pthread_mutex_lock(&timer->psh->mut);
pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut);
printf("Tache 2\n");
pthread_cond_signal(&timer->psh->synchro2);
pthread_mutex_unlock(&timer->psh->mut);
}
}
return NULL;
}
int main (void)
{
pthread_t ttimer;
pthread_t tread;
/* TIMER */
strTimer timer;
strShared shtimer;
shtimer.mut = PTHREAD_MUTEX_INITIALIZER;
shtimer.mut2 = PTHREAD_MUTEX_INITIALIZER;
shtimer.synchro = PTHREAD_COND_INITIALIZER;
shtimer.synchro2 = PTHREAD_COND_INITIALIZER;
timer.psh = &shtimer;
timer.wt = 1000;
/* Threads */
pthread_create(&ttimer, NULL, task_timer, &timer);
pthread_create(&tread, NULL, task_read, &timer);
pthread_join(ttimer,NULL);
pthread_join(tread,NULL);
return 0;
}
According to me, this code is the good way to achieve this aim. However, it is not working then I guess I did some mistakes. According to me it is working as below:
Both threads are created and executed in paralelism
Task_read take the mutex mut, wait for the signal synchro and free the mutex because the signal is never arrived
Task_timer take the mutex mut and display "Tache 1" on the standard output
Then, Task_timer sends the signal synchro and waits for the signal synchro2 (free the mutex because the signal is never arrived)
Task_read receives the signal synchro and take the mutex mut and displays "Tache 2"
Task_read sends the signal synchro2 and free the mutex mut and go to the begining of the While loop
Task_timer receives the signal synchro2 and free the mutex and go to the begining of the While loop
However, this is not happened like that. Actually, it seems the program gets stuck after displaying "Tache 1". Someone could explain me why this happens please ? I guess I think bad but I would like to understand ...
Many thanks,
esc39
If you are new to multi threading I suggest not using condition variables. You do not need to use any condition variable for the objective you described. So remove pthread_cond_wait and pthread_cond_signal lines in both threads.
Instead you can simply add the sleep function after unlocking the mutex in each thread. For e.g. task_read can be modified to:
pthread_mutex_lock(&timer->psh->mut);
printf("Tache 2\n");
pthread_mutex_unlock(&timer->psh->mut);
usleep(10000);
Let's see what happens when task_timer acquire lock first.
pthread_mutex_lock(&timer->psh->mut); /*acquires a lock*/ /*|*/
printf("Tache 1\n"); /*output*/ /*|*/
pthread_cond_signal(&timer->psh->synchro); /*sends a signal*/ /*|*/ /* no one is waiting for the signal on this cond, so the signal is ignored*/
pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut); /*releases lock and waits for signal*/ /*|*/ pthread_mutex_lock(&timer->psh->mut); /*acquires a lock*/
/*|*/ pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut); /*releases lock and waits for signal*/
/*|*/
/*|*/
/*|*/
/*|*/ printf("Tache 2\n"); /*never happens*/
pthread_mutex_unlock(&timer->psh->mut); /*never happens*/ /*|*/ pthread_cond_signal(&timer->psh->synchro2);
/*|*/ pthread_mutex_unlock(&timer->psh->mut);
Deadlock.
Simple recipe: put your pthread_cond_signal() calls outside the critical sections. Consider that as a rule of thumb. When you have a couple or more of threads synchronising with the same set of mutex/cond I can hardly imagine a scenario when it is reasonable to signal from critical section. Semantic of signal and broadcast is like: hey, guys, I'm done with my work on the critical resources, you may follow right on. When the thread is inside critical section, by signalling the cond it makes a false statement. Because it is not done.
BTW, in your case you need an additional flag telling which thread should run. And call the pthread_cond_wait() only in case the flag tells is the other thread's turn.
So, the basic algorithm for each thread would be (in pseudocode):
while(loop_again) {
do_processing_on_non_critical_resources(); /* it's optional */
lock(mutex);
while(not_my_turn) { /* explained later */
wait(cond,mutex);
}
do_processsing_on_critical_resources();
set_flag_to_other_thread();
unlock(mutex);
signal(cond);
do_processing_on_non_critical_resources(); /* it's optional */
}
The check for not_my_turn is in while loop instead of simple if check, because, according to the documentation, there could be spurious wakeup from
the pthread_cond_timedwait() or pthread_cond_wait():
When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
So, above you have a general case of synchronised thread. However for your case the answer from M.KHd is correct and sufficient.
Related
Basic question but for the sake of briefness, I have two threads where bar unblocks foo upon a certain condition, but even though the program runs fine to my surprise, shouldn't it cause deadlock if foo is run first which acquires the lock which means bar shouldn't be able to proceed further given the condition variable would never be true in foo?
pthread_mutex_t lock;
pthread_cond_t cv;
bool dataReady = false;
void foo(void *arg)
{
printf ("Foo...\n");
pthread_mutex_lock(&lock);
while (!dataReady)
{
pthread_cond_wait(&cv, &lock);
}
printf ("Foo unlocked...\n");
dataReady = true;
pthread_mutex_unlock(&lock);
}
void bar(void *arg)
{
printf ("Bar...\n");
pthread_mutex_lock(&lock);
sleep(3);
printf ("Data ready...\n");
dataReady = true;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&lock);
}
int main(void)
{
int main()
{
pthread_t t1,t2;
pthread_create(&t1,NULL,foo,NULL);
pthread_create(&t2,NULL,bar,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return 0;
}
Also in this context, using semaphore wouldn't make sense yes?
pthread_cond_wait(&cv, &lock); atomically releases the mutex when called and the re-acquires it when woken up.
From man 3 pthread_cond_wait:
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.
Upon successful return, the mutex shall have been locked and shall be
owned by the calling thread.
IMHO C++ documentation contains clearer explanation (I know the languages differ, but the principle of operation remains the same):
https://en.cppreference.com/w/cpp/thread/condition_variable
acquire a std::unique_lockstd::mutex, on the same mutex as used to protect the shared variable
either
check the condition, in case it was already updated and notified
execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is
atomically reacquired. The thread should then check the condition and
resume waiting if the wake up was spurious.
I'm studying on condition variables of Pthread. When I'm reading the explanation of pthread_cond_signal, I see the following.
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).
Till now I knew pthread_cond_signal() would make only one thread to wake up at a time. But, the quoted explanation says at least one. What does it mean? Can it make more than one thread wake up? If yes, why is there pthread_cond_broadcast()?
En passant, I wish the following code taken from UNIX Systems Programming book of Robbins is also related to my question. Is there any reason the author's pthread_cond_broadcast() usage instead of pthread_cond_signal() in waitbarrier function? As a minor point, why is !berror checking needed too as a part of the predicate? When I try both of them by changing, I cannot see any difference.
/*
The program implements a thread-safe barrier by using condition variables. The limit
variable specifies how many threads must arrive at the barrier (execute the
waitbarrier) before the threads are released from the barrier.
The count variable specifies how many threads are currently waiting at the barrier.
Both variables are declared with the static attribute to force access through
initbarrier and waitbarrier. If successful, the initbarrier and waitbarrier
functions return 0. If unsuccessful, these functions return a nonzero error code.
*/
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
static pthread_cond_t bcond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t bmutex = PTHREAD_MUTEX_INITIALIZER;
static int count = 0;
static int limit = 0;
int initbarrier(int n) { /* initialize the barrier to be size n */
int error;
if (error = pthread_mutex_lock(&bmutex)) /* couldn't lock, give up */
return error;
if (limit != 0) { /* barrier can only be initialized once */
pthread_mutex_unlock(&bmutex);
return EINVAL;
}
limit = n;
return pthread_mutex_unlock(&bmutex);
}
int waitbarrier(void) { /* wait at the barrier until all n threads arrive */
int berror = 0;
int error;
if (error = pthread_mutex_lock(&bmutex)) /* couldn't lock, give up */
return error;
if (limit <= 0) { /* make sure barrier initialized */
pthread_mutex_unlock(&bmutex);
return EINVAL;
}
count++;
while ((count < limit) && !berror)
berror = pthread_cond_wait(&bcond, &bmutex);
if (!berror) {
fprintf(stderr,"soner %d\n",
(int)pthread_self());
berror = pthread_cond_broadcast(&bcond); /* wake up everyone */
}
error = pthread_mutex_unlock(&bmutex);
if (berror)
return berror;
return error;
}
/* ARGSUSED */
static void *printthread(void *arg) {
fprintf(stderr,"This is the first print of thread %d\n",
(int)pthread_self());
waitbarrier();
fprintf(stderr,"This is the second print of thread %d\n",
(int)pthread_self());
return NULL;
}
int main(void) {
pthread_t t0,t1,t2;
if (initbarrier(3)) {
fprintf(stderr,"Error initilizing barrier\n");
return 1;
}
if (pthread_create(&t0,NULL,printthread,NULL))
fprintf(stderr,"Error creating thread 0.\n");
if (pthread_create(&t1,NULL,printthread,NULL))
fprintf(stderr,"Error creating thread 1.\n");
if (pthread_create(&t2,NULL,printthread,NULL))
fprintf(stderr,"Error creating thread 2.\n");
if (pthread_join(t0,NULL))
fprintf(stderr,"Error joining thread 0.\n");
if (pthread_join(t1,NULL))
fprintf(stderr,"Error joining thread 1.\n");
if (pthread_join(t2,NULL))
fprintf(stderr,"Error joining thread 2.\n");
fprintf(stderr,"All threads complete.\n");
return 0;
}
Due to spurious wake-ups pthread_cond_signal could wake up more than one thread.
Look for word "spurious" in pthread_cond_wait.c from glibc.
In waitbarrier it must wake up all threads when they all have arrived to that point, hence it uses pthread_cond_broadcast.
Can [pthread_cond_signal()] make more than one thread wake up?
That's not guaranteed. On some operating system, on some hardware platform, under some circumstances it could wake more than one thread. It is allowed to wake more than one thread because that gives the implementer more freedom to make it work in the most efficient way possible for any given hardware and OS.
It must wake at least one waiting thread, because otherwise, what would be the point of calling it?
But, if your applicaton needs a signal that is guaranteed to wake all of the waiting threads, then that is what pthread_cond_broadcast() is for.
Making efficient use of a multi-processor system is hard. https://www.e-reading.club/bookreader.php/134637/Herlihy,Shavit-_The_art_of_multiprocessor_programming.pdf
Most programming language and library standards allow similar freedoms in the behavior of multi-threaded programs, for the same reason: To allow programs to achieve high performance on a variety of different platforms.
I am working on the dining philosophers problem, where n philosophers take turns thinking and eating. I would like to have a version of this where the philosophers will eat in the order of their id: 0,1,2,3,4...,but my threads keep getting blocked. My threads start by calling PhilosopherThread().
void putDownChopsticks(int threadIndex){
//finished eating
pindex++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void pickUpChopsticks(int threadIndex){
pthread_mutex_lock(&lock);
while(pindex != threadIndex){
pthread_cond_wait(&cond, &lock);
}
//lets go eat
}
void eating(){
//put thread to sleep
}
void thinking(){
//put thread to sleep
}
void* PhilosopherThread(void *x){
int *index = x;
thinking(); //just puts thread to sleep to simulate thinking
pickUpChopsticks(*index);
eating(); //just puts thread to sleep to simulate eating
putDownChopsticks(*index);
return NULL;
}
I'm having a bit of trouble trying to get the philosophers in order. I can only get the first 2 threads to eat before the threads get blocked.
Edit: as far as i know im doing this right. I first lock the mutex, then I check if pindex is the current thread id, if its not the thread will wait until pindex does equal the id. Then the thread can go eat and once where done, we incread pindex, signal that the thread is done, and unlock the mutex.
This code sometimes works and sometimes does not. First, since you did not provide a complete program, here are the missing bits I used for testing purposes:
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t cond;
static pthread_mutex_t lock;
static pindex;
/* ... your code ... */
int main () {
int id[5], i;
pthread_t tid[5];
for (i = 0; i < 5; ++i) {
id[i] = i;
pthread_create(tid+i, 0, PhilosopherThread, id+i);
}
for (i = 0; i < 5; ++i) pthread_join(tid[i], 0);
exit(0);
}
The critical piece to notice is how you wake up the next philosopher:
pthread_cond_signal(&cond);
This call will only wake up one thread. But, which thread is at the discretion of the OS. Therefore, if it does not happen to wake up the philosopher that is supposed to wake up, no other philosopher is woken up.
A simple fix would be to wake up all waiting threads instead of just one. The philosophers that don't match will go back to waiting, and the one that is supposed to go next will go.
pthread_cond_broadcast(&cond);
However, since each thread knows which philosopher should wake up, you could change your solution to allow that to happen. One way could be to implement a separate condition variable per philosopher, and use pthread_cond_signal() on the next philosopher's condition variable.
I am trying to learn how to use conditional variables properly in C.
As an exercise for myself I am trying to make a small program with 2 threads that print "Ping" followed by "Pong" in an endless loop.
I have written a small program:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
sleep(0.5);
printf("ping\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
pthread_cond_wait(&cond,&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_cond_wait(&cond,&lock);
pthread_mutex_lock(&lock);
sleep(0.5);
printf("pong\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
while(1){
sleep(1);
i++;
}
return EXIT_SUCCESS;
}
And when running this program the output I get is:
main
thread 1 started
thread 2 started
ping
Any idea what is the reason the program does not execute as expected?
Thanks in advance.
sleep takes an integer, not a floating point. Not sure what sleep(0) does on your system, but it might be one of your problems.
You need to hold the mutex while calling pthread_cond_wait.
Naked condition variables (that is condition variables that don't indicate that there is a condition to read somewhere else) are almost always wrong. A condition variable indicates that something we are waiting for might be ready to be consumed, they are not for signalling (not because it's illegal, but because it's pretty hard to get them right for pure signalling). So in general a condition will look like this:
/* consumer here */
pthread_mutex_lock(&something_mutex);
while (something == 0) {
pthread_cond_wait(&something_cond, &something_mutex);
}
consume(something);
pthread_mutex_unlock(&something_mutex);
/* ... */
/* producer here. */
pthread_mutex_lock(&something_mutex);
something = 4711;
pthread_cond_signal(&something_cond, &something_mutex);
pthread_mutex_unlock(&something_mutex);
It's a bad idea to sleep while holding locks.
T1 and T2 are not valid functions to use as functions to pthread_create they are supposed to take arguments. Do it right.
You are racing yourself in each thread between cond_signal and cond_wait, so it's not implausible that each thread might just signal itself all the time. (correctly holding the mutex in the calls to pthread_cond_wait may help here, or it may not, that's why I said that getting naked condition variables right is hard, because it is).
First of all you should never use sleep() to synchronize threads (use nanosleep() if you need to reduce output speed). You may need (it's a common use) a shared variable ready to let each thread know that he can print the message. Before you make a pthread_cond_wait() you must acquire the lock because the pthread_cond_wait() function shall block on a condition variable. It shall be called with mutex locked by the calling thread or undefined behavior results.
Steps are:
Acquire the lock
Use wait in a while with a shared variable in guard[*]
Do stuffs
Change the value of shared variable for synchronize (if you've one) and signal/broadcast that you finished to work
Release the lock
Steps 4 and 5 can be reversed.
[*]You use pthread_cond_wait() to release the mutex and block the thread on the condition variable and when using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed because spurious wakeups may occur. watch more here
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 1){
pthread_cond_wait(&cond,&lock);
}
printf("ping\n");
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 0){
pthread_cond_wait(&cond,&lock);
}
printf("pong\n");
ready = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return EXIT_SUCCESS;
}
You should also use pthread_join() in main instead of a while(1)
I'm trying to implement a blocking queue using POSIX threads. Important code segments are shown below. I tried to run this program. The thread trying to remove an element from the queue goes to sleep when there are no elements in the queue and wakes up again without any signal from the thread that adds an element into the queue (This I conclude because I did not start any thread that adds an element into the queue). The thread woke up again goes to sleep and this process repeats. What am I doing wrong? Please some one tell me what I am missing here?
struct rqueue
{
int qsize;
int capacity;
pthread_mutex_t lock;
pthread_cond_t not_empty;
pthread_cond_t not_full;
};
remove_element_method:
pthread_mutex_lock(&rq->lock);
while(rq->qsize == 0){
perror("Q size is zero going to sleep");
pthread_cond_wait(&rq->not_empty);
perror("woke up");
}
// some code
pthread_cond_signal(&rq->not_full);
pthread_mutex_unlock(&rq->lock);
add_element_method:
pthread_mutex_lock(&rq->lock);
if(rq->capacity != -1 ){
while(rq->qsize == rq->capacity){
pthread_cond_wait(&rq->not_full);
}
}
//some code
pthread_cond_signal(&rq->not_empty);
pthread_mutex_unlock(&rq->lock);
pthread_cond_wait() takes two arguments -- the second is the mutex you're holding. You're only passing it one argument.
Also, did you initialize the mutex and condition variables using pthread_mutex_init() and pthread_cond_init()?