Skip to content
Advertisement

Does context switching works everytime, or does it result in unexpected behaviour?

In the below code my friend has stimulated a dead lock situation with context switching and mutex lock in linux.

#include <stdio.h>
#include <pthread.h>
pthread_mutex_t l1, l2;
void* func1();
void* func2();

int main()
{
    pthread_mutex_init(&l1, NULL);
    pthread_mutex_init(&l2, NULL);
    pthread_t t1, t2;
    pthread_create(&t1, NULL, func1, NULL);
    pthread_create(&t2, NULL, func2, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}

void* func1()
{
    pthread_mutex_lock(&l1);
    printf("nl1 locked in func 1"); // 1
    sleep(1);
    printf("ntrying to Lock l2 in func 1"); // 2
    pthread_mutex_lock(&l2);
}

void* func2()
{
    pthread_mutex_lock(&l2);
    printf("nl2 locked in func 2"); // 3
    sleep(1);
    printf("ntrying to Lock l1 in func 2"); // 4
    pthread_mutex_lock(&l1);
}

The problem is, after execution it printed Statement 1,3 and 4 But the correct output should have been statements 1,3 and 2

But when I change the value of sleep in func2 to sleep(4) It works fine.

And if I don’t write statement 2 and 4, after execution statement 1 is printed, but statements 1 and 3 should be printed.

Later after changing the func2 sleep(1) to sleep(4), switching it back to sleep(1) becomes correct working state…

Is all of this unexpected behaviour or is there a reason for this to be happening… Or a simple solution to correct all these behaviours would help me to understand. Thanks.

Advertisement

Answer

When you’re spawning threads there’s no guarantee that the threads will start executing in the order you spawned them. Sometimes it will happen, other times not. There’s no guarantee that 1 comes before 3. The only thing you’re guaranteed that func1 will be called in its own thread at any point after your call to pthread_create and pthread_join will not return until func1 returns in that thread. Same goes for func2. You are definitely not guaranteed that one of the threads will start running before the other.

sleep is not a sufficient synchronization mechanism. sleep is defined to have the process wait at least X seconds. It’s completely legal for the operating system to make your process wait for 10 times more. Unlikely, but it can happen. Especially on a busy system. Mix sleep and threads and anything can happen. Since it’s quite likely (but definitely not guaranteed) that the threads will run very close in time to each other, and timers in your system don’t have infinite precision, it’s quite likely that their sleep will be scheduled to end at the “same time” (“same time” is a very dangerous term, but in this case it means the same tick of some timer interrupt). So the threads will be awakened together, with no guarantees which will be awakened before the other. And regardless which one gets awakened before the other there’s still no telling which of those will start running first. Any luck you had with one of the threads running before the other will definitely run out here.

You’re not flushing your stdout properly by having the newlines at the beginning of the printfs instead of at the end (where does this come from? so many people do this in stackoverflow questions for no reason whatsoever). Add a newline at the end of printfs and since your stdout is most likely line buffered, the printfs will flush at the end of the line.

You also have a bunch of mutexes with no apparent function other than causing a deadlock at the end.

In fact, the way the code is written, it’s perfectly possible (although quite unlikely) that func2 starts running in a thread, locks l2, prints and sleeps and prints again, locks l1 and returns before any thread has started running func1. This will lead to func1 not printing anything because it will hang trying to lock l1.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement