I am trying to synchronize one main thread with N children threads. After some reading, I used condition_variable and unique_lock. However, I always get the errors condition_variable::wait: mutex not locked: Operation not permitted or unique_lock::unlock: not locked: Operation not permitted, in OS X. In Linux, I get Operation not permitted only.
To be clearer: my goal is to get a sequence of prints:
main thread, passing to 0
thread 0, passing back to main
main thread, passing to 0
thread 0, passing back to main
...
for each of the four threads.
I adapted the code from the example in http://en.cppreference.com/w/cpp/thread/condition_variable. This example uses unlock after wait, and it works wonderfully with only one thread other than main (N=1). But when adapted to work with N>1 threads, the error above happens.
Yam Marcovic said in the comments that I should not use unlock. But then, why does the cppreference example use it? And why does it work well with one main and one other threads?
Here is the code:
#include <cstdio>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
constexpr int N_THREADS = 4;
constexpr int N_ITER = 10;
bool in_main[N_THREADS] = {false};
void fun(mutex *const mtx, condition_variable *const cv, int tid){
for(int i=0; i<N_ITER; i++) {
unique_lock<mutex> lk(*mtx);
// Wait until in_main[tid] is false
cv->wait(lk, [=]{return !in_main[tid];});
// After the wait we own the lock on mtx, which is in lk
printf("thread %d, passing back to main\n", tid);
in_main[tid] = true;
lk.unlock(); // error here, but example uses unlock
cv->notify_one();
}
}
int main(int argc, char *argv[]) {
// We are going to create N_THREADS threads. Create mutexes and
// condition_variables for all of them.
mutex mtx[N_THREADS];
condition_variable cv[N_THREADS];
thread t[N_THREADS];
// Create N_THREADS unique_locks for using the condition_variable with each
// thread
unique_lock<mutex> lk[N_THREADS];
for(int i=0; i<N_THREADS; i++) {
lk[i] = unique_lock<mutex>(mtx[i]);
// Create the new thread, giving it its thread id, the mutex and the
// condition_variable,
t[i] = thread(fun, &mtx[i], &cv[i], i);
}
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
// Wait until in_main[tid] is true
cv[tid].wait(lk[tid], [=]{return in_main[tid];});
// After the wait we own the lock on mtx[tid], which is in lk[tid]
printf("main thread, passing to %d\n", tid);
in_main[tid] = false;
lk[tid].unlock(); // error here, but example uses unlock
cv[tid].notify_one();
}
for(int i=0; i<N_THREADS; i++)
t[i].join();
return 0;
}
Sample output:
thread 0, passing back to main
main thread, passing to 0
thread 1, passing back to main
thread 0, passing back to main
main thread, passing to 1
thread 2, passing back to main
thread 1, passing back to main
main thread, passing to 2
thread 2, passing back to main
thread 3, passing back to main
main thread, passing to 3
main thread, passing to 0
thread 3, passing back to main
libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: unique_lock::unlock: not locked: Operation not permitted
Abort trap: 6
you are trying to unlock your mutexes many times! look at the code carefully:
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
where N_ITER is 10 and N_THREADS is 4 always, because they are constexpr
we get:
for(int i=0; i < 40; i++) {
int tid=i % 4; // Thread id
so, when i = 0 the mutex in lk[0] is unlocked, and then when i=4 then tid = 4%4 so again tid = 0 and you are unlocking it again! std::system_error is thrown in this case.
plus, why are all of these C-Pointers anyway? it's not like anyof them can be null at any time.. switch to references..
also, usually when dealing with array indexes the convention is to use size_t and not int.
I found what the problem is. This question Using std::mutex, std::condition_variable and std::unique_lock helped me.
Constructing a unique_lock is acquiring the unique_lock too. So it must be done inside the loop, just before calling wait. The function fun looks the same, but main now looks like this:
int main(int argc, char *argv[]) {
// We are going to create N_THREADS threads. Create mutexes and
// condition_variables for all of them.
mutex mtx[N_THREADS];
condition_variable cv[N_THREADS];
thread t[N_THREADS];
// Create N_THREADS unique_locks for using the condition_variable with each
// thread
for(int i=0; i<N_THREADS; i++) {
// Create the new thread, giving it its thread id, the mutex and the
// condition_variable,
t[i] = thread(fun, &mtx[i], &cv[i], i);
// DO NOT construct, therefore acquire, a unique_lock
}
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
// Acquire the unique_lock here
unique_lock<mutex> lk(mtx[tid]);
// Wait until in_main[tid] is true
cv[tid].wait(lk, [=]{return in_main[tid];});
// After the wait we own the lock on mtx[tid], which is in lk[tid]
printf("main thread, passing to %d\n", tid);
in_main[tid] = false;
lk.unlock(); // error here, but example uses unlock
cv[tid].notify_one();
}
for(int i=0; i<N_THREADS; i++)
t[i].join();
return 0;
}
The only difference is that the unique_lock is constructed inside the loop.
Related
so i want the program to ouput 1\n2\n1\n2\n1\n2\n but it seems to get stuck somewhere. But when i debug it and set a breackpoint at cv1.notify_one() right after declaring t2 it executes ??
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1" << endl;
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2" << endl;
cv1.notify_one();
}
});
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
There are several flaws:
You want to guard your output. Therefor you need just one mutex so only one thread can do their work at a time.
You are potentially missing out notifications to your condition variables.
Your global unique_locks aquire the locks of the mutexs in their constructors. So you are holding the locks the whole time and no thread can make progress. Your global unique_locks aquire the locks of the mutexs in their constructors. This is done in the main thread. T1 and T2 are unlocking them through the condition_variable. This is undefined behaviour (thread that owns mutex must unlock it).
This is a recipe to use the condition variable approach correctly:
Have a condition you are interested in. In this case some kind of variable to remember who's turn it is.
Guard this variable by a (ONE!) mutex
Use a (ONE!) condition_variable in conjunction with the mutex of point 2 and the condition of point 1.
This ensures:
There is at any time only one thread which can look and/or change the condition you have.
If a thread is reaching the point in code where it possibly waits for the condition variable, it first checks the condition. Maybe the thread does not even need to go to sleep since the condition he wanna wait for is already true. To do so, the thread has to aquire the mutex, check the condition and decides what to do. While doing so, he owns the lock. The condition cant change because the thread has the lock itself. So you cant miss out a notification.
This leads to the following code ( see live here ):
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
int main(int argc, char** argv)
{
condition_variable cv;
mutex mtx;
bool runt1 = true;
bool runt2 = false;
constexpr int COUNT = 3;
thread t1([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt1; });
cout << "1" << endl;
runt1 = false;
runt2 = true;
lck.unlock();
cv.notify_one();
}
});
thread t2([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt2; });
cout << "2" << endl;
runt1 = true;
runt2 = false;
lck.unlock();
cv.notify_one();
}
});
t1.join();
t2.join();
return 0;
}
I think you have a data race between your threads starting and the call to cv1.notify_one(); in main().
Consider the case when cv1.notify_one() call happens before thread 1 has started and called cv1.wait(). After that no one calls cv1.notify anymore and your cv-s are just waiting. This is called Lost Wake-up.
You need a mechanism to wait in main till both threads have started, then execute cv1.notify()
Below is an example using int and a mutex.
#include "pch.h"
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
condition_variable cv1, cv2;
mutex m;
const int COUNT = 3;
enum Turn
{
T1,
T2
};
int main(int argc, char** argv)
{
mutex thread_start_mutex;
int num_started_threads = 0;
Turn turn = T1;
thread t1([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck1(m);
// wait till main thread calls notify
cv1.wait(lck1, [&] { return turn == T1;});
cout << "1 a really long string" << endl;
turn = T2; // next it's T2's turn
}
cv2.notify_one();
}
});
thread t2([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck2(m);
cv2.wait(lck2, [&] {return turn == T2;});
cout << "2 some other stuff to test" << endl;
turn = T1;
}
cv1.notify_one();
}
});
unique_lock<std::mutex> lck(thread_start_mutex);
// wait until both threads have started
cv1.wait(lck, [&] { return num_started_threads == 2; });
lck.unlock();
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
Also it's unclear why you have two mutexes that are locked outside of main. I usually think of a mutex as something that is protected a resource that should not be accessed concurrently. Seems like the idea was to protect the cout calls, for which you should use one mutex, that each thread will lock, do the cout, unlock and notify the other one.
Edit
My original answer had exact same issue between calls to t1.notify() and t2.wait().
If t1.notify() was called before thread 2 was waiting, thread 2 never got woken up.
To address this I added an enum "Turn" which indicates who's turn it is, and each wait condition now checks if it's their turn or not.
If it is, they are not waiting and just printing out, so even if notify was missed they'd still do their task. If it is not their turn, they'll block until the other thread sets turn variable and calls notify.
NOTE: This demonstrates a good example/practice that it's usually much better to have a condition when using cv.wait(). This both makes intentions clear, and avoids both Lost Wake-up and Spurious Wake-ups.
NOTE 2 this solution might be overly complicated, and in general condition variables and mutexes are unlikely the best approach for this problem.
The other answer is right conceptually but still has another race condition. I ran the code and it would still deadlock.
The issue is that t1 is created, but it does not get to cv1.wait(lck1) until after the cv1.notify_one() executes. Thus your two threads sit together forever waiting. You demonstrate this when you put your breakpoint on that line, allowing the thread to catch up. Also, this issue persists when one thread finishes but doesn't give the other time to call wait() so it just calls notify_one. This can be seen, also fixed* (used loosely), by adding some usleep(100) calls from unistd.h.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1\n";
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2\n";
usleep(100);
cv1.notify_one();
}
});
usleep(1000);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
EDIT: To do better would be to check for waiting threads, which is not built into the mutexes you use. The proper way might be to create your own mutex wrapper class and include that functionality in the class, but for simplicity sake, I just made a waiting variable.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2, cv3;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
int waiting = 0;
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv1.wait(lck1);
cout << "1\n";
waiting--;
if(!waiting)
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv2.wait(lck2);
cout << "2\n";
waiting--;
if(!waiting)
usleep(100);
cv1.notify_one();
}
});
if(!waiting)
usleep(100);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
I need feedback on my code for following statement, am I on right path?
Problem statement:
a. Implement a semaphore class that has a private int and three public methods: init, wait and signal. The wait and signal methods should behave as expected from a semaphore and must use Peterson's N process algorithm in their implementation.
b. Write a program that creates 5 threads that concurrently update the value of a shared integer and use an object of semaphore class created in part a) to ensure the correctness of the concurrent updates.
Here is my working program:
#include <iostream>
#include <pthread.h>
using namespace std;
pthread_mutex_t mid; //muted id
int shared=0; //global shared variable
class semaphore {
int counter;
public:
semaphore(){
}
void init(){
counter=1; //initialise counter 1 to get first thread access
}
void wait(){
pthread_mutex_lock(&mid); //lock the mutex here
while(1){
if(counter>0){ //check for counter value
counter--; //decrement counter
break; //break the loop
}
}
pthread_mutex_unlock(&mid); //unlock mutex here
}
void signal(){
pthread_mutex_lock(&mid); //lock the mutex here
counter++; //increment counter
pthread_mutex_unlock(&mid); //unlock mutex here
}
};
semaphore sm;
void* fun(void* id)
{
sm.wait(); //call semaphore wait
shared++; //increment shared variable
cout<<"Inside thread "<<shared<<endl;
sm.signal(); //call signal to semaphore
}
int main() {
pthread_t id[5]; //thread ids for 5 threads
sm.init();
int i;
for(i=0;i<5;i++) //create 5 threads
pthread_create(&id[i],NULL,fun,NULL);
for(i=0;i<5;i++)
pthread_join(id[i],NULL); //join 5 threads to complete their task
cout<<"Outside thread "<<shared<<endl;//final value of shared variable
return 0;
}
You need to release the mutex while spinning in the wait loop.
The test happens to work because the threads very likely run their functions start to finish before there is any context switch, and hence each one finishes before the next one even starts. So you have no contention over the semaphore. If you did, they'd get stuck with one waiter spinning with the mutex held, preventing anyone from accessing the counter and hence release the spinner.
Here's an example that works (though it may still have an initialization race that causes it to sporadically not launch correctly). It looks more complicated, mainly because it uses the gcc built-in atomic operations. These are needed whenever you have more than a single core, since each core has its own cache. Declaring the counters 'volatile' only helps with compiler optimization - for what is effectively SMP, cache consistency requires cross-processor cache invalidation, which means special processor instructions need to be used. You can try replacing them with e.g. counter++ and counter-- (and same for 'shared') - and observe how on a multi-core CPU it won't work. (For more details on the gcc atomic ops, see https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
class semaphore {
pthread_mutex_t lock;
int32_t counter;
public:
semaphore() {
init();
}
void init() {
counter = 1; //initialise counter 1 to get first access
}
void spinwait() {
while (true) {
// Spin, waiting until we see a positive counter
while (__atomic_load_n(&counter, __ATOMIC_SEQ_CST) <= 0)
;
pthread_mutex_lock(&lock);
if (__atomic_load_n(&counter, __ATOMIC_SEQ_CST) <= 0) {
// Someone else stole the count from under us or it was
// a fluke - keep trying
pthread_mutex_unlock(&lock);
continue;
}
// It's ours
__atomic_fetch_add(&counter, -1, __ATOMIC_SEQ_CST);
pthread_mutex_unlock(&lock);
return;
}
}
void signal() {
pthread_mutex_lock(&lock); //lock the mutex here
__atomic_fetch_add(&counter, 1, __ATOMIC_SEQ_CST);
pthread_mutex_unlock(&lock); //unlock mutex here
}
};
enum {
NUM_TEST_THREADS = 5,
NUM_BANGS = 1000
};
// Making semaphore sm volatile would be complicated, because the
// pthread_mutex library calls don't expect volatile arguments.
int shared = 0; // Global shared variable
semaphore sm; // Semaphore protecting shared variable
volatile int num_workers = 0; // So we can wait until we have N threads
void* fun(void* id)
{
usleep(100000); // 0.1s. Encourage context switch.
const int worker = (intptr_t)id + 1;
printf("Worker %d ready\n", worker);
// Spin, waiting for all workers to be in a runnable state. These printouts
// could be out of order.
++num_workers;
while (num_workers < NUM_TEST_THREADS)
;
// Go!
// Bang on the semaphore. Odd workers increment, even decrement.
if (worker & 1) {
for (int n = 0; n < NUM_BANGS; ++n) {
sm.spinwait();
__atomic_fetch_add(&shared, 1, __ATOMIC_SEQ_CST);
sm.signal();
}
} else {
for (int n = 0; n < NUM_BANGS; ++n) {
sm.spinwait();
__atomic_fetch_add(&shared, -1, __ATOMIC_SEQ_CST);
sm.signal();
}
}
printf("Worker %d done\n", worker);
return NULL;
}
int main() {
pthread_t id[NUM_TEST_THREADS]; //thread ids
// create test worker threads
for(int i = 0; i < NUM_TEST_THREADS; i++)
pthread_create(&id[i], NULL, fun, (void*)((intptr_t)(i)));
// join threads to complete their task
for(int i = 0; i < NUM_TEST_THREADS; i++)
pthread_join(id[i], NULL);
//final value of shared variable. For an odd number of
// workers this is the loop count, NUM_BANGS
printf("Test done. Final value: %d\n", shared);
const int expected = (NUM_TEST_THREADS & 1) ? NUM_BANGS : 0;
if (shared == expected) {
puts("PASS");
} else {
printf("Value expected was: %d\nFAIL\n", expected);
}
return 0;
}
#include<pthread.h>
#include<stdio.h>
int num_threads=3;
int state=0;
pthread_cond_t cond;
pthread_mutex_t mutex;
void* threadA(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 1 || state == 2) pthread_cond_wait(&cond,&mutex);
printf("Thread A\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void* threadB(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 0 || state == 2)pthread_cond_wait(&cond,&mutex);
printf("Thread B\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void* threadC(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 1 || state == 0) pthread_cond_wait(&cond,&mutex);
printf("Thread C\n\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
int main() {
pthread_t tid[3];
pthread_cond_init(&cond,NULL);
pthread_mutex_init(&mutex,NULL);
pthread_create(&tid[0],NULL,threadA,NULL);
pthread_create(&tid[1],NULL,threadB,NULL);
pthread_create(&tid[2],NULL,threadC,NULL);
return 0;
}
QUESTION: With the above code, I wish to print
threaA threadB threadC sequentially 5 times.
But the answer is undeterministic. While the order
of threads is maintained, answers are not printed 5 times.
Please help!!!
As #mch mentioned in the comment, you need to wait for the threads to finish before allowing the main() function to return:
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
Now, after you add the joins above to the end of main(), your program will most often hang. This happens because the pthread_cond_signal() doesn't wake up all threads waiting on that condition variable. If the wrong thread is woke up (e.g. threadC signals the condition, but the thread that gets notified is not threadA), then all threads will be waiting on the condition and there will be nobody to signal that condition.
To fix this, you need to make sure all threads are woke up each time and let each thread decide on it's own if it is its turn or not (by that while(state...) pthread_cond_wait(...);). To do this, you can replace the calls to pthread_cond_signal() with calls to pthread_cond_broadcast(), which unblocks all threads currently blocked on that condition.
I am new to conditional variables and get deadlock if not using pthread_cond_broadcast().
#include <iostream>
#include <pthread.h>
pthread_mutex_t m_mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
bool ready = false;
void* print_id (void *ptr )
{
pthread_mutex_lock(&m_mut);
while (!ready) pthread_cond_wait(&cv, &m_mut);
int id = *((int*) ptr);
std::cout << "thread " << id << '\n';
pthread_mutex_unlock(&m_mut);
pthread_exit(0);
return NULL;
}
condition is changed here!
void go() {
pthread_mutex_lock(&m_mut);
ready = true;
pthread_mutex_unlock(&m_mut);
pthread_cond_signal(&cv);
}
It can work if I change the last line of go() to pthread_cond_broadcast(&cv);
int main ()
{
pthread_t threads[10];
// spawn 10 threads:
for (int i=0; i<10; i++)
pthread_create(&threads[i], NULL, print_id, (void *) new int(i));
go();
for (int i=0; i<10; i++) pthread_join(threads[i], NULL);
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&cv);
return 0;
}
The expected answer (arbitrary order) is
thread 0
....
thread 9
However, on my machine (ubuntu), it prints nothing.
Could anyone tell me the reason? Thanks.
From the manual page (with my emphasis):
pthread_cond_signal restarts one of the threads that are waiting on the condition variable cond. If no threads are waiting on cond, nothing happens. If several threads are waiting on cond, exactly one is restarted, but it is not specified which.
pthread_cond_broadcast restarts all the threads that are waiting on the condition variable cond. Nothing happens if no threads are waiting on cond.
Each of your ten threads is waiting on the same condition. You only call go() once - that's from main(). This calls pthread_cond_signal, which will only signal one of the threads (an arbitrary one). All the others will still be waiting, and hence the pthread_join hangs as they won't terminate. When you switch it to pthread_cond_broadcast, all of the threads are triggered.
I am new to multithreading and hence started with a small program. The job expected from the program is, to print integers one after the other by means of two threads in such a way that one thread should print one number and the other thread should print the next number and this process should continue till a maximum number defined.
For this I wrote a small program and iam facing dead lock. I tried to find mutex owner using gdb but it;s just printing $3 = 2 when I execute print mutex command.
Here is the source code:
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <signal.h>
const int MAX_NUM = 13;
pthread_cond_t cond[1] = {PTHREAD_COND_INITIALIZER,};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int Count = 0;
using namespace std;
void* thread1(void*)
{
do {
cout<<"inside thread 1 abt to acquire lock"<<endl;
// Increment counter in thread1
pthread_mutex_lock(&mutex);
cout<<"inside thread 1 blocked"<<endl;
pthread_cond_wait(&cond[0],&mutex);
cout<<"after pthread_cond_wait in thread1"<<endl;
pthread_cond_signal(&cond[1]);
if(Count < MAX_NUM)
{
Count++;
pthread_mutex_unlock(&mutex);
cout<<"Printing from thread 1"<<endl;
cout<<Count<<endl;
}
else
{
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
}while(1);
}
void* thread2(void*)
{
do{
cout<<"inside thread 2 abt to acquire lock"<<endl;
pthread_mutex_lock(&mutex);
cout<<"inside thread 2 blocked"<<endl;
pthread_cond_wait(&cond[1],&mutex);
// Increment counter in thread2
pthread_cond_signal(&cond[0]);
if(Count < MAX_NUM)
{
Count++;
pthread_mutex_unlock(&mutex);
cout<<"Printing from thread 2"<<endl;
cout<<Count<<endl;
}
else
{
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
}while(1);
}
int main()
{
pthread_t t[2];
void* (*fun[2])(void*);
fun[0]=thread1;
fun[1]=thread2;
for (int i =0 ; i < 2; ++i)
{
pthread_create(&t[i],NULL,fun[i],NULL);
}
cout<<"threads created"<<endl;
pthread_cond_signal(&cond[0]);
cout<<"In main after sending signal"<<endl;
pthread_join(t[0],NULL);
pthread_join(t[1],NULL);
pthread_exit(NULL);
}
Output is:
inside thread 1 abt to acquire lock
inside thread 1 blocked
inside thread 2 abt to acquire lock
inside thread 2 blocked
threads created
In main after sending signal
I expected main() thread to send a signal to thread 1 which does it's job (i.e. updating counter) and then passes signal to thread 2 which does it's job (i.e. updating counter) and passes signal to thread 1. This process should continue until max number is reached. If max number is reached each process unlocks mutex and exits gracefully.
Please help me. I really tried a lot nothing worked.
the line
pthread_cond_t cond[1] = {PTHREAD_COND_INITIALIZER,};
defines an array of size 1, but later on you use cond[1], the second entry in the array, which is undefined. Did you mean
pthread_cond_t cond[2] = {PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER};
This looks like an unlucky typo. (Due to the preceeding MAX_NUM = 13?)
In addition to #TooTone's observation you need to understand one aspect of how condition variables work. If you signal a condition variable when no thread is blocked on it nothing will happen. The condition variable has no memory, so if a little bit later a thread blocks on in it will stay locked until the condition is signaled again.
Your main function signals cond[0] right after it started the threads, so it is possible that the threads haven't reached their blocking point yet. Or if they are blocked then it can happen that when one thread signals the other one that other one isn't blocked. So after you fix your condition variable array you will see that the test runs a bit more, but eventually deadlocks again.
I was able to make it work using a quick & dirty trick of introducing delays before signaling the condition variables. This gives the threads time to reach their blocking points before the signaling happens. Here is the modified code:
const int MAX_NUM = 13;
pthread_cond_t cond[2] = {PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int Count = 0;
using namespace std;
void* thread1(void*)
{
do {
cout<<"inside thread 1 abt to acquire lock"<<endl;
// Increment counter in thread1
pthread_mutex_lock(&mutex);
cout<<"inside thread 1 blocked"<<endl;
pthread_cond_wait(&cond[0],&mutex);
cout<<"after pthread_cond_wait in thread1"<<endl;
if(Count < MAX_NUM)
{
Count++;
pthread_mutex_unlock(&mutex);
cout<<"Printing from thread 1"<<endl;
cout<<Count<<endl;
usleep(1000000);
pthread_cond_signal(&cond[1]);
}
else
{
pthread_mutex_unlock(&mutex);
usleep(1000000);
pthread_cond_signal(&cond[1]);
pthread_exit(NULL);
}
}while(1);
}
void* thread2(void*)
{
do{
cout<<"inside thread 2 abt to acquire lock"<<endl;
pthread_mutex_lock(&mutex);
cout<<"inside thread 2 blocked"<<endl;
pthread_cond_wait(&cond[1],&mutex);
// Increment counter in thread2
if(Count < MAX_NUM)
{
Count++;
pthread_mutex_unlock(&mutex);
cout<<"Printing from thread 2"<<endl;
cout<<Count<<endl;
usleep(1000000);
pthread_cond_signal(&cond[0]);
}
else
{
pthread_mutex_unlock(&mutex);
usleep(1000000);
pthread_cond_signal(&cond[0]);
pthread_exit(NULL);
}
}while(1);
}
int main()
{
pthread_t t[2];
void* (*fun[2])(void*);
fun[0]=thread1;
fun[1]=thread2;
for (int i =0 ; i < 2; ++i)
{
pthread_create(&t[i],NULL,fun[i],NULL);
}
cout<<"threads created"<<endl;
usleep(1000000);
pthread_cond_signal(&cond[0]);
cout<<"In main after sending signal"<<endl;
pthread_join(t[0],NULL);
pthread_join(t[1],NULL);
pthread_exit(NULL);
}
Using condition variables for this kind of thing isn't the best idea. Semaphores are better suited to the task because those do have memory and remember their signaled state even if nobody is waiting on them when they are signaled.