Is there an alternative way to be sure that the threads are ready to recieve the broadcast signal. I want to replace the Sleep(1) function in main.
#include <iostream>
#include <pthread.h>
#define NUM 4
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_t tid[NUM];
void *threads(void *arg){
int tid = (int)arg;
while(true){
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);
//do some work
cout<<"Thread: "<<tid<<endl;;
pthread_mutex_unlock(&mutex);
}
}
int main(){
for(int i=0;i<NUM;i++){
pthread_create(&tid[i],NULL,threads,(void*)i);
}
Sleep(1);
pthread_cond_broadcast(&cond);
Sleep(1);
pthread_cond_broadcast(&cond);
Sleep(1);
pthread_cond_broadcast(&cond);
return 0;
}
I tried memory barriers before pthread_cond_wait and i thought of using an counter, but nothing worked for me yet.
Condition variables are usually connected to a predicate. In the other threads, check if predicate is already fulfilled (check while holding the mutex protecting the predicate), if so, do not wait on the condition variable. In main, acquire mutex, change predicate while holding the mutex. Then release mutex and signal or broadcast on the condvar. Here is a similar question: Synchronisation before pthread_cond_broadcast
Here is some example code:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cassert>
#define NUM 4
#define SIZE 256
using std::cout;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_t tid[NUM];
int work_available;
void *threads(void *arg)
{
int tid = *((int*)arg);
while (1) {
pthread_mutex_lock(&mutex);
while (work_available == 0) {
// While loop since cond_wait can have spurious wakeups.
pthread_cond_wait(&cond, &mutex);
cout << "Worker " << tid << " woke up...\n";
cout << "Work available: " << work_available << '\n';
}
if (work_available == -1) {
cout << "Worker " << tid << " quitting\n";
pthread_mutex_unlock(&mutex); // Easy to forget, better to use C++11 RAII mutexes.
break;
}
assert(work_available > 0);
work_available--;
cout << "Worker " << tid << " took one item of work\n";
pthread_mutex_unlock(&mutex);
//do some work
sleep(2); // simulated work
pthread_mutex_lock(&mutex);
cout << "Worker " << tid << " done with one item of work.\n";
pthread_mutex_unlock(&mutex);
}
}
int main()
{
work_available = 0;
int args[NUM];
for (int i=0; i<NUM; i++) {
args[i] = i;
pthread_create(&tid[i], NULL, threads, (void*)&args[i]);
}
const int MAX_TIME = 10;
for (int i = 0; i < MAX_TIME; i++)
{
pthread_mutex_lock(&mutex);
work_available++;
cout << "Main thread, work available: " << work_available << '\n';
pthread_mutex_unlock(&mutex);
pthread_cond_broadcast(&cond);
sleep(1);
}
pthread_mutex_lock(&mutex);
cout << "Main signalling threads to quit\n";
work_available = -1;
pthread_mutex_unlock(&mutex);
pthread_cond_broadcast(&cond);
for (int i = 0; i < NUM; i++)
{
pthread_join(tid[i], NULL);
}
return 0;
}