Domanda

I have a program that I want to be able to go between different thread. In this example I am just trying to print stuff from a string, and stuff from another string just to see that I am being sent between two threads. I am unable to do this with my code because it hangs up. Ideally I want to work with multiple signals and be able to go back and forth. I have spent about four hours on this and I just can't get it to work, I am thinking that just using global variables would be much more simple and then I would only have to work with a mutex instead of a condition variable, or even no mutex at all.

I just can't get these fickle mutex and condition variable to behave as expected.

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

char word1[10] = "Hello";
char word2[10] = "world";

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // mutual exclusion lock for prod
//pthread_mutex_t mutexSigalProd = PTHREAD_MUTEX_INITIALIZER;
//pthread_cond_t signalToProd = PTHREAD_COND_INITIALIZER;
pthread_cond_t addToQ = PTHREAD_COND_INITIALIZER;


void * prod(void *arg) { printf("Entering prod \n");
    pthread_mutex_lock(&mutex);
    int i = 0;

    while (i < 10) {
        printf("PROD adding line: %c \t", word1[i]);
        i++;
        if (i % 2 == 0)
        {
            pthread_mutex_unlock(&mutex);
            pthread_cond_signal(&addToQ);
            pthread_cond_wait(&addToQ, &mutex);
        }
    }
    pthread_exit(NULL);
}


void * con(void *arg) 
{
    printf("Entering con \n");
    pthread_mutex_lock(&mutex);
    //pthread_mutex_unlock(&mutex);
    pthread_cond_wait(&addToQ, &mutex);
    int i = 0;

    while (i < 10) 
    {
        printf ("CON adding line: %c \t", word2[i]);
        i++;
        if (i % 2 != 0)
        {
            //pthread_mutex_unlock(&mutex);
            pthread_cond_signal(&addToQ);
            pthread_cond_wait(&addToQ, &mutex);
        }
    }

    pthread_exit(NULL);
}

int main()
{
    pthread_t threadp1;        // Thread objects
    pthread_t threadp2;
    pthread_t threadc1;

    pthread_create(&threadp1, NULL, prod, NULL);  // start first producer thread
    //pthread_create(&threadp2, NULL, con1, NULL); // start second producer thread
    pthread_create(&threadc1, NULL, con,  NULL); // start consumer thread
    pthread_exit(NULL);              // main thread quits
}
È stato utile?

Soluzione

The race condition in your code is:

Prod sends a signal without checking whether Con is waiting for it. If Con is not yet waiting for the signal, then the signal has no effect (from the man page - "The pthread_cond_broadcast() and pthread_cond_signal() functions shall have no effect if there are no threads currently blocked on cond.").

And then you have both Con and Prod wait for each other. Hence the deadlock.

See if the following code works:

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

char word1[10] = "Hello";
char word2[10] = "world";
int con_started = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // mutual exclusion lock for prod
pthread_cond_t addToQ = PTHREAD_COND_INITIALIZER;

void * prod(void *arg) {
    printf("PROD: Entering prod \n");
    fflush(stdout);
    int i = 0;
    int j = 1;
    while (i < 5) {
        printf("PROD adding line: %c \n", word1[i]);
        fflush(stdout);
        i++;
        if (i % 2 == 0)
        {
            pthread_mutex_lock(&mutex);
            while(!con_started)
            {
                pthread_mutex_unlock(&mutex);
                sched_yield();
                printf("PROD: Waiting for CON to wait.\n");
                fflush(stdout);
                pthread_mutex_lock(&mutex);
            }
            printf("PROD: Sending signal %d\n\n", j);
            fflush(stdout);
            pthread_cond_signal(&addToQ);
            printf("PROD: Will wait now \n\n");
            fflush(stdout);
            pthread_cond_wait(&addToQ, &mutex);
            printf("PROD received signal %d\n\n", j);
            fflush(stdout);
            pthread_mutex_unlock(&mutex);
            j++;
        }
    }
    sched_yield();
    sleep(1);
    printf("PROD: Sending signal %d\n\n", j);
    fflush(stdout);
    pthread_cond_signal(&addToQ);
    pthread_exit(NULL);
}


void * con(void *arg)
{
    int i = 0;
    int j=1;
    printf("CON: Entering con \n");
    fflush(stdout);
    pthread_mutex_lock(&mutex);
    con_started = 1;
    printf("CON: Will wait now\n \n");
    fflush(stdout);
    pthread_cond_wait(&addToQ, &mutex);
    printf("CON received first signal\n\n");
    fflush(stdout);
    while (i < 5)
    {
        printf ("CON adding line: %c \n", word2[i]);
        fflush(stdout);
        if (i % 2 != 0)
        {
            //pthread_mutex_unlock(&mutex);
            printf("CON: Sending signal %d\n\n", j);
            fflush(stdout);
            pthread_cond_signal(&addToQ);
            j++;
            printf("CON: Will wait now \n\n");
            fflush(stdout);
            pthread_cond_wait(&addToQ, &mutex);
            printf("CON received signal %d\n\n", j);
            fflush(stdout);
            pthread_mutex_unlock(&mutex);
        }
        i++;
    }
    pthread_exit(NULL);
}

int main()
{
    pthread_t threadp1;        // Thread objects
    pthread_t threadc1;
    pthread_create(&threadp1, NULL, prod, NULL);  // start first producer thread
    pthread_create(&threadc1, NULL, con,  NULL); // start consumer thread
    pthread_join(threadp1, NULL);
    printf("MAIN: threadp1 completed.\n");
    fflush(stdout);
    pthread_join(threadc1, NULL);
    printf("MAIN: threadc1 completed.\n");
    fflush(stdout);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top