简体   繁体   中英

pthread_cond_signal not reaching to the other thread before the calling thread exits

I'm trying to simulate context switching through synchronization between threads (starting with 2, for now) such that each thread acts as a process and the process switching occurs at every TIMESLICE interval (3 ms, for now). The thread switching by executing only one thread at a time is running perfectly although, the issue comes when the first thread exits but the pthread_cond_signal that is executed pre-exit of the calling thread does not wake up the pthread_cond_wait of the other thread.

Here is the C program:

#include<stdio.h> //for printf
#include<pthread.h> //for threads, mutual exclusion, conditional wait and signalling
#include<time.h> //for accurate clock time
#include<limits.h> //for min-max limits of several data types
#include<inttypes.h> //for using uint64_t data type

#define bool int
#define true 1
#define false 0

#define TIMESLICE 3000000 //nanoseconds to define milliseconds
#define BILLION 1000000000L

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock_t = PTHREAD_MUTEX_INITIALIZER;
int numProcWait = 2;

void *threadFunction(void *arg) {
    int i;
    uint64_t diff=0;
    bool locked,unlockCheck=true; // locked for synchronizing the thread withing itself
    // unlock check for if the for loop exits without unlocking the mutex and without signalling the other thread   

    struct timespec start, end;
    pthread_cond_wait(&cond,&lock_t);
    pthread_mutex_lock(&lock);

    clock_gettime(CLOCK_MONOTONIC, &start);

    locked = true;
    for (i = 0; i < INT_MAX/2048; i++) {

        if(locked==false) {
            pthread_mutex_lock(&lock);
            printf("Lock acquired by Thread id: %lu\n",pthread_self());
            locked = true;
            diff = 0;
            clock_gettime(CLOCK_MONOTONIC, &start);
        }
        clock_gettime(CLOCK_MONOTONIC, &end);
        diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
        unlockCheck = true;

        if(diff > TIMESLICE) {

            if(i==INT_MAX-1)
                unlockCheck = false;

            if(numProcWait>1) {
                locked = false;     
                printf("Lock released by Thread id: %lu\n",pthread_self());
                printf("Diff Time: %" PRIu64 " ms\n\n",diff/1000000);

                pthread_mutex_unlock(&lock);
                printf("Unlocking from thread Successful! Thread ID: %lu\n\n",pthread_self());
                pthread_cond_signal(&cond);
                printf("Waiting Thread id: %lu\n\n",pthread_self());
                pthread_cond_wait(&cond,&lock_t);
                printf("Received Signal Successful! Thread ID: %lu\n\n",pthread_self());
            }
        }
    }
    //this condition would occur false on a very rare case
    if(unlockCheck) {
        printf("Lock released from out of the loop by Thread id: %lu\n\n",pthread_self());
        //this condition is executed but it doesn't wakes up the pthread_cond_wait function of the other thread.
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&cond);     
    }

    printf("EXITING THREAD: %lu\n\n",pthread_self());
    numProcWait--;
    printf("Number of processes waiting: %d\n\n",numProcWait);
    return NULL;
}

int main() {

    pthread_t tid[2];
    uint64_t diff;
    struct timespec start, end;

    clock_gettime(CLOCK_MONOTONIC, &start);

    pthread_create(&tid[0], NULL, threadFunction, NULL);
    pthread_create(&tid[1], NULL, threadFunction, NULL);

    sleep(1);
    pthread_cond_broadcast(&cond);

    pthread_join(tid[0], NULL);
    printf("Thread 1 EXITED. No. of Waiting Processes: %d\n",numProcWait);
    //pthread_cond_signal(&cond);   
    pthread_join(tid[1], NULL);
    printf("Thread 2 EXITED. No. of Waiting Processes: %d\n",numProcWait);
    clock_gettime(CLOCK_MONOTONIC, &end);
    diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;

    printf("Total Run Time: %" PRIu64 " ms\n",diff/1000000);
    pthread_mutex_destroy(&lock);
    pthread_cond_destroy(&cond);
}

Off the top of my head: The code's problem seems to be that it uses two mutexes, lock and lock_t. The code locks lock and calls pthread_cond_wait with lock_t as arg.

A good idea may be to delete the lock_t mutex and only use one mutex.

You need to lock the mutex before calling condition wait and signal as below.

Wait:

pthread_mutex_lock(&lock_t);
pthread_cond_wait(&cond,&lock_t);
pthread_mutex_unlock(&lock_t);

Signal:

pthread_mutex_lock(&lock_t);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock_t);

you are using conditional-variables wrong

first of all, you need to acquire the lock before calling pthread_cond_wait()

but then your logic is wrong,

            pthread_mutex_unlock(&lock);
            printf("Unlocking from thread Successful! Thread ID: %lu\n\n",pthread_self());
            pthread_cond_signal(&cond);

            // you need to lock here, but its undefined which thread will
            // acquire the lock first, so its possible, that the same thread
            // will acquire the lock instantly again
            // -> mutex are not fair!
            pthread_mutex_lock(&lock_t);                

            printf("Waiting Thread id: %lu\n\n",pthread_self());
            pthread_cond_wait(&cond,&lock_t);
            printf("Received Signal Successful! Thread ID: %lu\n\n",pthread_self());

could either add a sleep (bad idea) or, set up a global variable, which indicates, which thread is currently running.

int current_thread=0;

and then you need to adjust every cond_wait to current_thread = NEXT_THREAD; pthread_mutex_unlock(&lock); printf("Unlocking from thread Successful! Thread ID: %lu\\n\\n",pthread_self()); pthread_cond_signal(&cond);

            pthread_mutex_lock(&lock_t);                
            while (current_thread != YOUR_LOCAL_THREAD_ID) {
                pthread_cond_wait(&cond,&lock_t);
            }

            printf("Received Signal Successful! Thread ID: %lu\n\n",pthread_self());

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