Home > other >  Why does these two threads not run synchronously?
Why does these two threads not run synchronously?

Time:01-14

I have the following program that spawns two threads to print_something() and they both repeatedly print a specific string: thread 1 prints "Hi\n" and thread 2 prints "Bye\n":

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

void *print_something(int *k) 
{
    int n = 100;

    int i;
    if (*k) {
        for (i = 0; i < 100; i  ) {
            printf("Hi\n");
        }       
    } else {
        for (i = 0; i < 100; i  ) {
            printf("Bye\n");
        }
    }
}

int main()
{
    int x = 1, y = 0;
    pthread_t t1, t2;

    pthread_create(&t1, NULL, print_something, &x);
    pthread_create(&t2, NULL, print_something, &y);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("End of program.\n");

    return 0;
}

I expected them to run synchronously wherein the output in the terminal would be random such as:

Hi
Hi
Bye
Hi
Bye
...

But instead I always get thread 1 to finish its printing first before thread 2 will start printing:

Hi
Hi
...
Hi
Hi
Bye
Bye
...
Bye
Bye
End of program.

Why is the first thread blocking the second thread from printing?

CodePudding user response:

Why is the first thread blocking the second thread from printing?

Who says it's blocking? Maybe starting a new thread takes long enough that the first additional thread (running in parallel with the original thread) finishes its printing (to stdout's buffer) before the second additional thread arrives at the point of trying to print anything.

On the other hand, POSIX does specify that the stdio functions perform operations on streams as if there was a lock associated with each stream that a thread must obtain upon entry to the function and releases upon exit. Thus, the first thread may indeed be blocking the second via the lock associated with stdout.

Moreover, when a thread unlocks a lock and then immediately tries to re-acquire the same lock, there is a high probability for that thread to succeed immediately despite other threads contending for the lock. As a result, when an entire loop body starts with acquiring a lock and ends with releasing that lock -- as is the case in your code for the lock associated stdout -- it is common for one thread to be able to monopolize the lock for many loop iterations.

CodePudding user response:

I expected them to run synchronously wherein the output in the terminal would be random such as:

That's an unreasonable expectation. If two people each need to put in a hundred screws and are sharing a screwdriver, do you think they should hand off the screwdriver after each screw? It only makes sense to hand off the screwdriver when the one holding the screwdriver is tired.

Each thread spends the vast majority of its time accessing the console output stream. It can only do this by excluding the other thread. The behavior you expect would be atrocious.

Would they run on the same core? That would require a context switch after every line of output -- the worst performance possible for this code. Would they run on two cores? That would mean each core is waiting for the other core to finish with the console for about half the time -- also horrible performance.

Simply put, you expected your system to find a terrible way to do what you asked it to do. It found a much more efficient way -- letting one thread keep the console, finish what it was doing, and then letting the other go.

  •  Tags:  
  • Related