简体   繁体   中英

pthread mutex lock/unlock in while(1)

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...

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM