0

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);
}
burglarhobbit
  • 1,860
  • 2
  • 17
  • 32
  • 1
    Possible duplicate of [understanding of pthread\_cond\_wait() and pthread\_cond\_signal()](http://stackoverflow.com/questions/16522858/understanding-of-pthread-cond-wait-and-pthread-cond-signal) – Andrew Henle Oct 21 '16 at 15:38
  • 1
    Your code causes undefined behavior for calling `pthread_cond_wait()` without holding the relevant `pthread_mutex_t`. – EOF Oct 21 '16 at 16:21

3 Answers3

1

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);
MayurK
  • 1,925
  • 14
  • 27
0

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.

Bjorn A.
  • 1,148
  • 9
  • 12
0

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());
Domso
  • 970
  • 1
  • 10
  • 22