1
votes

Let's say I had 4 threads, a producer and three consumers, a single mutex and a single condition variable, every consumer runs the same function that does the below:

mutexlock(mutex)
signal[i] = 1;
while(signal[i] == 1) {
condwait(cond, mutex)
}
mutexunlock(mutex)

And the producer does the below

if(signal == 1) 
{
set 0 - atomically using CAS
mutexlock(mutex)
condbroadcast(cond)
mutexunlock(mutex)
}

Let's say if more than one consumer were in that lock, wouldn't they fight for the cond variable? Should I create one for each thread or can p_thread condition variables be shared accross multiple threads without any race conditions?

2
You issued a broadcast. Every thread actively waiting on that condition signal will be bumped to the line waiting on the mutex. And fyi, this "code" make no sense if the signal in the first text is the signal in the second (one is an array, the other... not). And even if they are somehow supposed to be the same, the if() in the second should be under the protection of the mutex, as it contains the predicate state, which is the entire point of the mutex. Wrapping the actual condition notify or broadcast is pointless. The mutex is to protect the predicate; not the cvar.WhozCraig
The second code batch has indeed signal as an array too, I just forgot to put it, also the second signal is protected by a CAS condition - which I believe is less heavy than locking for every time I have to broadcast the condition...Whiteclaws
Real Code : It's What's For Dinner.WhozCraig
Any particular reason to use pthread_const_broadcast() over pthread_cond_signal()?alk
@alk because multiple threads may be sleeping at the same time, and I'm not sure to make all of them up with cond_signal, if they wake up and their signal condition is still up, they just go back to sleepWhiteclaws

2 Answers

0
votes

When you create a muti-thread program,they share the resource signal[i] and all the three thread will compete for the resources.When signal[i] == 0,the threads which didn't get the resource will be put into the queue of the condition variable.And when you send a broadcast,all the waiting threads in the condition variable will weak up and compete for the resouce.Here is a tourial for muti-thread beginner in C.

0
votes

Semantic of pthread_cond_wait is to release acquired mutex and block on conditional variable. When signal arrives, block is released, then pthread_cond_wait acquires the lock on mutex.

So, in your case, when you use pthread_cond_broadcast all threads blocked on conditional will move past this point, but after that one of them will be granted lock on mutex. Which one? It depends on the order the scheduler wakes them up after being unblocked and the pthread implementation in case two or more threads try to acquire the lock at the some moment. It's safe to consider it's random.

If you replace pthread_cond_broadcast with pthread_cond_signal, the signal will be delivered to some threads. Yes, it is expected to be one, but sometimes more than one can be released from conditional variable. Still, the thread (or threads) to deliver signal to will be chosen by scheduler. And if more than one is waked up from cond waiting, they will fight for the mutex. As previously - you can consider the result as random.

Let's look into documentation:

If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked.

On a multi-processor, it may be impossible for an implementation of pthread_cond_signal() to avoid the unblocking of more than one thread blocked on a condition variable.

BTW, I am quite curious. There are several questions about conditional variables recently (are you guys all doing a project for your uni or what?) and in every question I have seen in last 24 hours I have seen a following pattern for signalling:

pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond); /* or signal */
pthread_mutex_unlock(&mutex);

when waiting threads have:

pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);
/* do something */
pthread_mutex_unlock(&mutex);

What's the reason behind that?

Waiting threads wait on cond, mutex is released. So signalling thread acquires lock on mutex, signals other threads. In this very moment they - still being inside the pthread_cond_wait progress past the cond blockade, then they try to acquire the lock on mutex. And, of course, they cannot, because the lock is hold by signalling thread. Then, signalling thread releases mutex and waiting threads can finally process by acquiring - one by one - the mutex.

For signalling writer and waiting consumers this pattern should be as below.

For writer:

while(loop_condition) {
    prepare_data() /* it could be a long process */
    lock(&mutex);
    add_data_to_queue(); /* fast, inside critical section */
    unlock(&mutex);
    signal(&cond); /* or broadcast */
}

For consumers:

while(consumer_loop_condition) {
    lock(&mutex);
    while(!data_ready_to_process()) {
        wait(&cond,&mutex);
    }
    fetch_data(); /* fast, still inside critical section */
    unlock(&mutex);
    if(got_data) {
        process_data(); /* could be a long process */
    }
}

Please see also this answer for some more explanation on cond/mutexes and some example code to play with.