Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pthread mutex lock/unlock in while(1)

Tags:

c

mutex

pthreads

I'm trying to write very simple multi threading program just to get the catch of it but I fail to understand what exactly is wrong in one of the cases. So:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

char string[100];
pthread_t thr_id_rd;
pthread_t thr_id_wr;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond, cond1;
int read = 0;

void *thread_rd()
{
    pthread_mutex_lock(&lock);
    while (1) {
        pthread_cond_wait(&cond, &lock);
        printf("rd: entered: %s\n", string);
        pthread_cond_signal(&cond1);
    }
    pthread_mutex_unlock(&lock);
}

void *thread_wr()
{
    pthread_mutex_lock(&lock);
    while (1) {
        printf("wr: enter something: ");
        scanf("%s", string);
        pthread_cond_signal(&cond);
        pthread_cond_wait(&cond1, &lock);
    }
    pthread_mutex_unlock(&lock);
}

int main(int argc, char *argv[])
{
    pthread_create(&thr_id_rd, NULL, thread_rd, NULL);
    pthread_create(&thr_id_wr, NULL, thread_wr, NULL);

    pthread_join(thr_id_rd, NULL);
    pthread_join(thr_id_wr, NULL);

    return 0;
}

The above seems to work correctly. But when I edit the two threads like this:

void *thread_rd()
{
    while (1) {
        pthread_mutex_lock(&lock);
        pthread_cond_wait(&cond, &lock);
        printf("rd: entered: %s\n", string);
        pthread_cond_signal(&cond1);
        pthread_mutex_unlock(&lock);
    }
}

void *thread_wr()
{
    while (1) {
        pthread_mutex_lock(&lock);
        printf("wr: enter something: ");
        scanf("%s", string);
        pthread_cond_signal(&cond);
        pthread_cond_wait(&cond1, &lock);
        pthread_mutex_unlock(&lock);
    }
}

I'm getting undefined behavior - sometimes it's OK sometimes the program is stuck. According the man pages pthread_cond_wait must be called with mutex locked but there is no such restriction for _cond_signal (Question: What is the best practice?). So I decided to call it with mutex locked...

Obviously I'm complete newbie so please excuse my stupid question :( I'll be very grateful if someone can explain this to me...

like image 346
Meh Avatar asked Nov 04 '12 12:11

Meh


People also ask

Can mutex lock by one thread unlock from another?

Attempting to unlock a mutex locked by a different thread results in undefined behavior. Attempting to unlock an unlocked mutex results in undefined behavior. This type of mutex provides error checking. A thread attempting to relock this mutex without first unlocking it will return with an error.

Can a mutex be locked more than once?

Deadlock! If a thread which had already locked a mutex, tries to lock the mutex again, it will enter into waiting list of that mutex which results in deadlock.

Does Pthread mutex lock wait?

If the mutex is already locked by another thread, the thread waits for the mutex to become available. The thread that has locked a mutex becomes its current owner and remains the owner until the same thread has unlocked it.

Does Pthread cond wait unlock mutex?

The pthread_cond_wait() function atomically unlocks mutex and performs the wait for the condition. In this case, atomically means with respect to the mutex and the condition variable and another threads access to those objects through the pthread condition variable interfaces.


1 Answers

pthread conditional variable signals are not persistent. If you signal when nothing is waiting for the signal, the signal will be lost. So you could see something like this:

WR: Lock
WR: Read input
WR: Signal cond
WR: Wait for cond1 (implicitly unlocks)
RD: Lock
RD: Wait for cond (implicitly unlocks)

At this point you have a deadlock - both threads are waiting for signals which will never come.

The usual pattern with condvars is to have a flag (or some other persistent condition) paired with the conditional variable. You can then do a loop like:

while (!flag) pthread_cond_wait(&cond, &lock);

To signal, you set the flag, and then signal the condvar to wake up any waiters.

In your case you can actually use string as your flag - have string == NULL be the wake-up condition paired with cond1 and string != NULL paired with cond. Now if your reader thread enters the lock late it'll see that string != NULL and not wait on the condvar.

like image 169
bdonlan Avatar answered Oct 12 '22 02:10

bdonlan