Okay so in the code below there at least two major problems which should be corrected.
#define COUNT_LIMIT 12
pthread_mutex_t c_mutex;
pthread_cond_t cond_cv;
int count=0;
void *inc_count(void *param)
{
int i=0;
for (i=0;i<14;i++) {
count++;
if (count==COUNT_LIMIT)
pthread_cond_signal(&cond_cv);
}
}
void *watch_count(void *param)
{
pthread_mutex_lock(&c_mutex);
while (count<COUNT_LIMIT) {
pthread_cond_wait(&cond_cv, &c_mutex);
printf("watch_count(): signal received.\n");
}
pthread_mutex_unlock(&c_mutex);
pthread_exit(NULL);
}
The first problem that I spotted was in the watch_count() function at the while loop, the logic there is wrong because when count is 12, it will not be less than COUNT_LIMIT. So to fix this I would change it to
while(count <= COUNT_LIMIT)
Would the other thing be unlocking the mutex after signalling watch_count()?
Otherwise, I cannot find any other thing that is wrong. I event tried reading this but I had trouble understanding it.
One error is that the inc_count() function needs to have the mutex locked while it accesses the count variable.
Your suggested change to the while() loop is incorrect - it should not call pthread_cond_wait() again if count == COUNT_LIMIT, so the original test was correct.
The other error might be that c_mutex and cond_cv are not initialised correctly.
Related
I'm trying to update a global variable in the main function and have a thread tell me when this variable is positive.
The code: https://pastebin.com/r4DUHaUV
When I run it, only 2 shows up though 1 and 2 should be the correct answer.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_t tid;
pthread_mutex_t mtx;
pthread_cond_t cond;
int nr=0;
void* function(void* arg)
{
pthread_mutex_lock(&mtx);
printf("Number in thread : %d \n",nr);
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
}
int main()
{
pthread_mutex_init(&mtx,NULL);
pthread_create(&tid,NULL,function,NULL);
int i;
for(i=0;i<3;i++)
{
int isPos=0;
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
if(nr>0)
isPos=1;
if(isPos==1)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
}
pthread_join(tid,NULL);
return 0;
}
As I mentioned in general comment, I'll repeat here:
There is no guarantee the main thread won't go off, locking the mutex,
changing nr, signaling the cv (whether or not anyone is actually
waiting on it), and unlocking the mutex, all before the child thread
even locks the mutex, much less starts waiting on the cv. In that
case, nr can be 1 (or 2, etc) when the child finally gets the mutex.
That means your while loop will be skipped (nr<=0 is not true), and
whatever the current value of nr is will be printed on the way out.
I've run this several times, and gotten 1x1, 1x2, and 2x2, multiple
times.
A simple fix for this involves using the cv/mtx pair you've set up for monitoring for changes from main to also monitor startup-start from function. First the code:
The Code
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int nr = -1;
void* function(void* arg)
{
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
// now start waiting (which will unlock the mutex as well, which means
// the main thread will be be able to acquire it and check nr safely
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
// now we know the child is ready to receive signals
int i;
for(i=0;i<3;i++)
{
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
int isPos = (nr>0);
pthread_mutex_unlock(&mtx);
if (isPos)
pthread_cond_signal(&cond);
}
pthread_join(tid,NULL);
return 0;
}
How It Works
The initial value of nr is established as -1. Only the child thread will change this directly to 0, and even then only under the protection of the predicate mutex.
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
Note that after the above three lines, the child still owns the mutex. It atomically releases it and begins waiting for notifications with the first entry into the subsequent loop:
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
Now, back in main, the startup creates the child thread, acquires the mutex, then monitors until nr is zero.
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
The only way to make it past this is when nr == 0. When that happens, the child must have changed it, but more importantly, it also must be waiting on the condition variable (that is how we got the mutex; remember?) From that point on, the code is similar. Worth noting, I use the pthread initializers to ensure the mutex and cvar are properly stood up. Your original post was missing the cvar initialization.
Lastly, doing multiple-predicate double-duty with a single cvar-mtx pair is easy to mess up, and can be very hard to detect edge cases when you did (mess up, that is). Be careful. This specific example is a hand-off sequence of duties, not concurrent duties, making it fairly trivial, so I'm comfortable in showing it.
Hope it helps.
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 am writing a program to test my understanding of condition variables. Basically, thread 0 checks if count is even, and if so, increments it. If not, then it signals thread 1 which increments the count variable. The process continues until count reaches 15. Here is my code:
#include <pthread.h>
#include <stdio.h>
#define numThreads 2
int count=0;
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
void *checkEven(void *threadId)
{ while(count<=15){
//lock the mutex
pthread_mutex_lock(&count_mutex);
printf("even_thread: thread_id=%d count=%d\n",threadId,count);
if(count%2==0){
count++;
}
else{
printf("Odd count found, signalling to odd thread\n");
pthread_cond_signal(&count_threshold_cv);
}
pthread_mutex_unlock(&count_mutex);
sleep(1);
}
}
void *checkOdd(void *threadId)
{
pthread_mutex_lock(&count_mutex); //obtain a lock
while(count<=15){
pthread_cond_wait(&count_threshold_cv, &count_mutex); //wait() relinquishes the lock
count++;
printf("odd_thread: thread_id=%d, count=%d\n",threadId,count);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
int main()
{
pthread_t threads[numThreads];
int rc;
int a=0;
int b=0;
pthread_create(&threads[0], NULL, checkEven, (void *)a);
pthread_create(&threads[1], NULL, checkEven, (void *)b);
pthread_join(0,NULL);
pthread_join(1,NULL);
pthread_exit(NULL);
}
Can someone tell me why I am getting segmentation fault(core dumped) error with this? I know that this error occurs when one process tries to violate the address space of some other process, but nothing beyond this.Can someone please help? Thanks!
You're passing a zero to pthread_join as the thread you want to join:
pthread_join(0,NULL);
You wanted:
pthread_join(threads[0],NULL);
pthread_join(threads[1],NULL);
You have several other bugs though. For one thing, your checkOdd code calls pthread_cond_wait even when it's that thread's turn.
You don't seem to understand condition variables. Specifically, you seem to think that somehow the condition variable will know whether or not the thing you are waiting for has happened. It does not -- condition variables are stateless. It's your job to keep track of what you're waiting for and whether or not it has happened.
I have written the following code to get the understanding of event ordering using pthreads and mutex. main function creates two threads which are associated to functions func1 and func2. Function func1 checks for the value of count and conditionally wait for func2 to signal it. Function func2 increments the count and when count reaches 50000, it signals func1.
Then func1 prints the value of count which is(or should be) at that time 50000.
But in actual output, along with 50000 some other values are also being printed. I am not getting any reason why is it so. What I think is, when func2 signals, func1 wakes up and execute from after the pthread_cond_wait statement, and so it should print only 50000. Please point out where I am wrong and what should be changed to get correct output?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_mutex_t evmutex;
pthread_cond_t evcond;
char a;
int count;
int N = 50000;
void *func1()
{
while(1)
{
pthread_mutex_lock(&evmutex);
if(count < N)
{
pthread_cond_wait(&evcond,&evmutex);
printf("%d\n",count);
count = 0;
}
pthread_mutex_unlock(&evmutex);
}
}
void *func2()
{
while(1)
{
pthread_mutex_lock(&evmutex);
count++;
if(count == N)
{
pthread_cond_signal(&evcond);
}
pthread_mutex_unlock(&evmutex);
}
}
int main ()
{
pthread_t ptd1,ptd2;
pthread_mutex_init(&evmutex,NULL);
pthread_cond_init(&evcond,NULL);
count = 0;
pthread_create(&ptd1,NULL,func1,NULL);
pthread_create(&ptd2,NULL,func2,NULL);
pthread_exit(NULL);
pthread_mutex_destroy(&evmutex);
pthread_cond_destroy(&evcond);
return 0;
}
You've not synchronized with the producer, func2(), and telling it to wait until the consumer, func1(), has processed the condition.
Nothing stops the producer from signalling the condition, re-acquiring the mutex, and incrementing the counter again. pthread_cond_signal doesn't mean your producer will halt and wait for the consumer to process.
This means the producer might increment the counter many times before your consumer gets scheduled and wakes up to print the current number.
You'd need to add another condition variable which the producer waits for after it's incremented the counter to N, and have the consumer signal that when it has processed the counter.
In addition to that, you need to handle spurious wakeups as other answers mentions.
Some implementations of pthread_cond_wait() suffer from spurious wake-ups, and because of this, it's common practice to use a while (cond) { pthread_cond_wait(...); } loop to work around this.
I found a good explanation of the problem and causes here: Why does pthread_cond_wait have spurious wakeups?
I've got some code that currently looks like this (simplified)
/* instance in global var *mystruct, count initialized to 0 */
typedef struct {
volatile unsigned int count;
} mystruct_t;
pthread_mutex_t mymutex; // is initialized
/* one thread, goal: block while mystruct->count == 0 */
void x(void *n) {
while(1) {
pthread_mutex_lock(&mymutex);
if(mystruct->count != 0) break;
pthread_mutex_unlock(&mymutex);
}
pthread_mutex_unlock(&mymutex);
printf("count no longer equals zero");
pthread_exit((void*) 0)
}
/* another thread */
void y(void *n) {
sleep(10);
pthread_mutex_lock(&mymutex);
mystruct->count = 10;
pthread_mutex_unlock(&mymutex);
}
This seems inefficient and wrong to me--but I don't know a better way of doing it. Is there a better way, and if so, what is it?
Condition variables allow you to wait for a certain event, and have a different thread signal that condition variable.
You could have a thread that does this:
for (;;)
{
if (avail() > 0)
do_work();
else
pthread_cond_wait();
}
and a different thread that does this:
for (;;)
{
put_work();
pthread_cond_signal();
}
Very simplified of course. :) You'll need to look up how to use it properly, there are some difficulties working with condition variables due to race conditions.
However, if you are certain that the thread will block for a very short time (in order of µs) and rarely, using a spin loop like that is probably more efficient.
A general solution is to use a POSIX semaphore. These are not part of the pthread library but work with pthreads just the same.
Since semaphores are provided in most other multi-threading APIs, it is a general technique that may be applied perhaps more portably; however perhaps more appropriate in this instance is a condition variable, which allows a thread to pend on the conditional value of a variable without polling, which seems to be exactly what you want.
Condition variables are the solution to this problem. Your code can be fairly easily modified to use them:
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
/* one thread, goal: block while mystruct->count == 0 */
void x(void *n) {
pthread_mutex_lock(&mymutex);
while (mystruct->count == 0)
pthread_cond_wait(&mycond, &mymutex);
printf("count no longer equals zero");
pthread_mutex_unlock(&mymutex);
pthread_exit((void*) 0)
}
/* another thread */
void y(void *n) {
sleep(10);
pthread_mutex_lock(&mymutex);
mystruct->count = 10;
pthread_cond_signal(&mycond);
pthread_mutex_unlock(&mymutex);
}
Note that you should generally keep the mutex locked while you act on the result - "consume" the event or similar. That's why I moved the pthread_mutex_unlock() to a point after the printf(), even though it doesn't really matter in this toy case.
(Also, in real code it might well make sense to put the mutex and condition variable inside mystruct).
You could use barriers.
You may also use semaphores to synchronize threads.