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);
}