pthreads: exclusive+concurrent functions (inverse semaphore) - c

I have code that locks every function (of a certain library), and which I would like to optimize. Given functions A and B, I don't mind any A running concurrently with any other A, or any B running concurrently with any other B, but no A can run while any B is running, and vice-versa. The thread count is dynamic and for reason out of my control I am forced to use static allocation for mutexes and conditional variables (i.e. PTHREAD_MUTEX_INITIALIZER).
I have a hunch that the most efficient approach is two conditional variables. Using pthread_mutex_trylock allows one function (i.e. A) to run in parallel while the other must be serialized. Also *trylock with static initialization is actually undefined behavior...
Edit:
Perhaps something like this? I'm not sure if this:
Can be simpler. After all, mutexes are implemented using semaphores, but it takes four mutexes and two conditional variables to implement what is basically an inverse semaphore.
Covers all race conditions.
Is "fair" (beyond default priority and scheduling)?
static int countA = 0;
static int countB = 0;
static pthread_mutex_t lockCountA = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t lockCountB = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t lockA = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t lockB = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
static pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
// for B(), just s/B/A/g
static void A(void) {
pthread_mutex_lock(&lockB);
while(countB)
pthread_cond_wait(&condB, &lockB);
pthread_mutex_lock(&lockCountA);
countA += 1;
pthread_mutex_unlock(&lockCountA)
doA();
pthread_mutex_lock(&lockCountA)
countA -= 1;
if countA == 0:
pthread_cond_signal(&condA);
mutex_unlock(&lockCountA)
mutex_unlock(&lockB);
}

Your solution has a race condition. Consider the case when both countA and countB are zero, and two threads simultaneously call A() and B(). The first thread locks lockB, the second thread locks lockA, both see the count they examine as zero, then proceed to increment their respective counts and proceed in error.
Another problem in your solution is that it uses pthread_cond_signal() which does not necessarily wake any more than one waiting thread, so if you have 10 threads waiting to enter B() but only one thread running A(), when the latter thread finishes only one B() thread is guaranteed to continue and the other 9 may wait indefinitely.
It also doesn't allow more than one thread to run doA() concurrently, since lockB is held over that call.
To fix the first problem, you can use one mutex that protects both countA and countB (because the shared state we must examine involves the combination of both these variables). At the same time, you might as well just use one condition variable too: the threads waiting on the condition variable must either be all waiting to enter A(), or all waiting to enter B(), but a mix of the two is impossible. Fixing the second problem just requires pthread_cond_broadcast(). That leads to the much simpler:
static int countA = 0;
static int countB = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void A(void)
{
pthread_mutex_lock(&lock);
while (countB)
pthread_cond_wait(&cond, &lock);
countA++;
pthread_mutex_unlock(&lock);
do_A();
pthread_mutex_lock(&lock);
countA--;
if (!countA)
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
This solution is correct, but is not "fair" - if there is a continuous stream of threads executing A() (such that a new one enters and increments countA before the previous thread has finished and decremented it) then the threads waiting to execute B() will be kept waiting forever. This may not be an issue in your particular use - for example, if you know that any thread that executes A() will eventually execute B(), then the starvation situation must eventually resolve.
Improving the system to prevent this starvation can be done by preventing new entries into A() while there are threads queued to enter B():
static int countA = 0;
static int countB = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int queuedA = 0;
static int queuedB = 0;
static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
void A(void)
{
pthread_mutex_lock(&lock);
while (queuedB)
pthread_cond_wait(&queue_cond, &lock);
while (countB)
{
queuedA++;
pthread_cond_wait(&cond, &lock);
queuedA--;
}
if (!queuedA)
pthread_cond_broadcast(&queue_cond);
countA++;
pthread_mutex_unlock(&lock);
do_A();
pthread_mutex_lock(&lock);
countA--;
if (!countA)
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
This prevents starvation because:
queuedB is always non-zero while there are any threads waiting on cond in B();
While queuedB is non-zero, no threads may increment countA, and therefore countA must eventually reach zero and allow the threads waiting on cond to proceed.
while countA is zero, no thread may increment queuedB and thus queuedB must eventually reach zero and allow the threads waiting on queue_cond to proceed.

Related

Problem in communication of three threads in C language (deadlock occurs)

I am creating a program in which i have 3 linked lists and I am trying to update or remove the nodes from these linked lists in these three threads. But the deadlock is occurring
The insertion and deletion is working fine. Here the three variables var1InUse,var2InUse and var3InUse are indicating that whether the 3 linked lists are in use or not(Not all three are use in the all threads). I am putting the threads on waiting based on var1InUse,var2InUse and var3InUse as you can see in the code. Sometimes this works fine but sometimes deadlock happens. I have searched for the solution on the internet but could find it.
Am I using the wait and signal methods correctly?
pthread variables declaration
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t t1cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t t2cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t t3cond = PTHREAD_COND_INITIALIZER;
int var1InUse=0,var2InUse=0,var3InUse=0;
THREAD 1
void* thread1(void* args){
while(var1InUse || var2InUse ) {
pthread_cond_wait(&t1cond,&myMutex);}
var1InUse=1,var2InUse=1;
while(1){
pthread_mutex_lock(&myMutex);
/*
some other code about adding and removing from
linkedlist
*/
var1InUse=0,var2InUse=0;
pthread_cond_signal(&t2cond);
pthread_cond_signal(&t3cond);
pthread_mutex_unlock(&myMutex);}
}
THREAD 2
void* thread2(void* args){
while(var1InUse || var2InUse || var3InUse) {
pthread_cond_wait(&t2cond,&myMutex);}
var1InUse=1,var2InUse=1,var3InUse=1;
while(1){
pthread_mutex_lock(&myMutex);
/*
some other code adding and removing from linkedlist
*/
var1InUse=0,var2InUse=0,var3InUse=0;
pthread_cond_signal(&t1cond);
pthread_cond_signal(&t3cond);
pthread_mutex_unlock(&myMutex);}
}
THREAD 3
void* thread3(void* args){
while(var1InUse || var3InUse ) {
pthread_cond_wait(&t3cond,&myMutex);}
var1InUse=1,var3InUse=1;
while(1){
pthread_mutex_lock(&myMutex);
/*
some other code adding and removing from linkedlist
*/
var1InUse=0,var3InUse=0;
pthread_cond_signal(&t1cond);
pthread_cond_signal(&t2cond);
pthread_mutex_unlock(&myMutex);}
}
MAIN METHOD
int main(){
pthread_t t1,t2,t3,t4;
pthread_mutex_init(&myMutex,0);
pthread_create(&t1,NULL,thread1,NULL);
pthread_create(&t2,NULL,thread2,NULL);
pthread_create(&t3,NULL,thread3,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
pthread_mutex_destroy(&myMutex);
return 0
}
I want the deadlock to be removed.
The mutex used by pthread_cond_wait() needs to locked before the function is called. Here is an extract from the man page:
The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. The application shall ensure that these functions are called with mutex locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust mutexes) or undefined behavior (for other mutexes) results.
Although pthread_cond_wait() unlocks the mutex internally, it is locked again before the function returns successfully:
Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.
Additionally, you should access the shared variables var1InUse, var2InUse and var3InUse with the mutex locked.
Here is a modified version of your thread1() that follows these rules. The modifications to the other thread start routines should be similar:
void* thread1(void* args){
pthread_mutex_lock(&myMutex);
while(var1InUse || var2InUse ) {
pthread_cond_wait(&t1cond,&myMutex);
}
var1InUse=1,var2InUse=1;
pthread_mutex_unlock(&myMutex);
while(1){
pthread_mutex_lock(&myMutex);
/*
some other code about adding and removing from linkedlist
*/
var1InUse=0,var2InUse=0;
pthread_cond_signal(&t2cond);
pthread_cond_signal(&t3cond);
pthread_mutex_unlock(&myMutex);
}
return NULL;
}
(I'm not entirely sure that the above is correct, because it's not entirely clear from the original code what the while(1) loop is supposed to do.)

unexpected behavior when using conditional variables (c, gcc)

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)

Using different mutex locks in threads

I have written the following program to implement two threads in POSIX. There is a global shared variable sum, which is being accessed by two different threads simultaneously. I have used mutex lock and unlock inside each thread while accessing the shared variable. I have a question. Here I have used the samed mutex lock (pthread_mutex_lock(&mutex))inside the two threads. What will Happen if I use two different mutex lock and unlock inside the threads (such as pthread_mutex_lock(&mutex)) in thread1 and pthread_mutex_lock(&mutex1) in thread2. I have commented out the line of confusion in the code.
My sample code fragment:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex1=PTHREAD_MUTEX_INITIALIZER;
int sum=0;
void * threadFunc1(void * arg)
{
int i;
for(i=1;i<100;i++)
{
printf("%s\n",(char*)arg);
pthread_mutex_lock(&mutex)
sum++;
pthread_mutex_unlock(&mutex)
sleep(1);
}
}
void * threadFunc2(void * arg)
{
int i;
for(i=1;i<100;i++)
{
printf("%s\n",(char*)arg);
pthread_mutex_lock(&mutex) //what will happen if I use mutex1 here
sum--;
pthread_mutex_lock(&mutex) //what will happen if I use mutex1 here
sleep(1);
}
}
int main(void)
{
pthread_t thread1;
pthread_t thread2;
char * message1 = "i am thread 1";
char * message2 = "i am thread 2";
pthread_create(&thread1,NULL,threadFunc1,(void*)message1 );
pthread_create(&thread2,NULL,threadFunc2,(void*)message2 );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return 0;
}
What is the basic difference between using the same mutex locks and different mutex lock in accessing a shared variable?
The purpose of the mutex is to prevent one thread from accessing the shared variable while another thread is, or might be, modifying it. The semantics of a mutex are that two threads cannot lock the same mutex at the same time. If you use two different mutexes, you don't prevent one thread from accessing the shared variable while another thread is modifying it, since threads can hold different mutexes at the same time. So the code will no longer be guaranteed to work.

Giving mutex to correct thread

If two threads are being blocked on a lock, how can you choose which get's it?
For example thread1 calls mutex_lock(aMut) but aMut is already locked so thread1 blocks. Along comes thread2 and it calls mutex lock on aMut and it blocks. How can it be ensured aMut is given to thread2?
here is my attempt that doesn't work
/*global variables*/
pthread_mutex_t aMut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_var = PTHREAD_COND_INITIIALIZER;
pthread_cond_t changeNumPrior = PTHREAD_COND_INITIIALIZER;
int highPriorityThreads = 0;
/*function that is passed to pthread_create()*/
void* functionThatIsPassedToPthreadCreate(void* arg)
{
bool highPriority = false;
if(arg->someConditionIsMet)
{
highPriorityThreads++;
highPriority = true;
}
pthread_mutex_lock(&changeNumPrior);
while(!highPriority && highPriorities > 0)//this doesn't work
{
pthread_cond_wait(&cond_var, &changeNumPrior);
}
pthread_mutex_unlock(&changeNumPrior);
pthread_mutex_lock(&aMut);//if this blocks, by the time this mutex is aquired, there now may be high priority threads
//code that requires exclusive access to shared resource protected by aMut
pthread_mutex_unlock(&aMut);
pthread_cond_signal(&cond_var);
}
Just saying "Now I want this task to be scheduled and now this one" is not possible, but some thread libraries allow to set the priority of tasks, so it will be favored when scheduling.
For pthreads, you can do this with pthread_getschedparam.

Check to see if a pthread mutex is locked or unlocked (After a thread has locked itself)

I need to see if a mutex is locked or unlocked in an if statement so I check it like this...
if(mutex[id] != 2){
/* do stuff */
}
but when I check it gcc gives me the following error:
error: invalid operands to binary != (have 'ptherad_mutex_t' and 'int')
So how can I check to see if the mutex is locked or not?
EDIT:
A key component to my problem is that my threads (by design) lock themselves right AFTER passing control to another thread. So when thread A passes control to thread B thread A is locked, thread B does some stuff, then when thread B is done it will unlock thread A.
The problem with this is that if thread B attempts to unlock thread A and thread A has not yet completed locking itself then the call to unlock is lost and thread A remains locked which causes a dead lock.
UPDATE:
I remade my program taking caf's suggestion but I am still running into problems. I have molded my program into the structure caf provided the best I can but I cannot even tell what is causing the dead lock now... I have created a new question here seeking help with my code.
Below is a runnable version of caf's suggestion. I made a small reordering in the function for thread a, without which both thread a and thread b would have been locked upon their creation, waiting for a condition that could never change.
#include <pthread.h>
int run_a = 0;
pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;
int run_b = 0;
pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;
void *a(void *);
void *b(void *);
int main(){
int status;
pthread_t thread_a;
pthread_t thread_b;
pthread_create(&thread_a, NULL, a, (void *)0);
pthread_create(&thread_b, NULL, b, (void *)0);
pthread_join(thread_a, (void **)&status);
pthread_join(thread_b, (void **)&status);
}
/* thread A */
void *a(void *i){
while (1) {
printf("thread A is running\n");
sleep(1);
/* unlock thread B */
pthread_mutex_lock(&lock_b);
run_b = 1;
pthread_cond_signal(&cond_b);
pthread_mutex_unlock(&lock_b);
/* wait for thread A to be runnable */
pthread_mutex_lock(&lock_a);
while (!run_a)
pthread_cond_wait(&cond_a, &lock_a);
run_a = 0;
pthread_mutex_unlock(&lock_a);
}
}
/* thread B */
void *b(void *i){
while (1) {
/* wait for thread B to be runnable */
pthread_mutex_lock(&lock_b);
while (!run_b)
pthread_cond_wait(&cond_b, &lock_b);
run_b = 0;
pthread_mutex_unlock(&lock_b);
printf("thread B is running\n");
sleep(1);
/* unlock thread A */
pthread_mutex_lock(&lock_a);
run_a = 1;
pthread_cond_signal(&cond_a);
pthread_mutex_unlock(&lock_a);
}
}
You can use pthread_mutex_trylock. If that succeeds, the mutex was unclaimed and you now own it (so you should release it and return "unheld", in your case). Otherwise, someone is holding it.
I have to stress though that "check to see if a mutex is unclaimed" is a very bad idea. There are inherent race conditions in this kind of thinking. If such a function tells you at time t that the lock is unheld, that says absolutely nothing about whether or not some other thread acquired the lock at t+1.
In case this is better illustrated with a code example, consider:
bool held = is_lock_held();
if (!held)
{
// What exactly can you conclude here? Pretty much nothing.
// It was unheld at some point in the past but it might be held
// by the time you got to this point, or by the time you do your
// next instruction...
}
Mutexes are not the right primitive for the scheme that you want to implement. You should be using condition variables:
int run_thread_a = 0;
pthread_mutex_t run_lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_a = PTHREAD_COND_INITIALIZER;
int run_thread_b = 0;
pthread_mutex_t run_lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_b = PTHREAD_COND_INITIALIZER;
/* thread A */
while (1) {
/* Wait for Thread A to be runnable */
pthread_mutex_lock(&run_lock_a);
while (!run_thread_a)
pthread_cond_wait(&run_cond_a, &run_lock_a);
run_thread_a = 0;
pthread_mutex_unlock(&run_lock_a);
/* Do some work */
/* Now wake thread B */
pthread_mutex_lock(&run_lock_b);
run_thread_b = 1;
pthread_cond_signal(&run_cond_b);
pthread_mutex_unlock(&run_lock_b);
}
/* thread B */
while (1) {
/* Wait for Thread B to be runnable */
pthread_mutex_lock(&run_lock_b);
while (!run_thread_b)
pthread_cond_wait(&run_cond_b, &run_lock_b);
run_thread_b = 0;
pthread_mutex_unlock(&run_lock_b);
/* Do some work */
/* Now wake thread A */
pthread_mutex_lock(&run_lock_a);
run_thread_a = 1;
pthread_cond_signal(&run_cond_a);
pthread_mutex_unlock(&run_lock_a);
}
Each thread will block in pthread_cond_wait() until the other thread signals it to wake up. This will not deadlock.
It can easily be extended to many threads, by allocating one int, pthread_cond_t and pthread_mutex_t per thread.
You can't compare a pthread_mutex_t with a int.
You can use
int pthread_mutex_trylock(pthread_mutex_t *mutex);
to check that.

Resources