hhy hhy - 1 month ago 16
C++ Question

Pthread freezes stdout?

Let's say there're two threads(pthread) in a C++ program:


  • the
    main thread

  • the
    child thread



What the program does is simple:


  1. Bind the two threads to two different cores.

  2. Set the priorities of the two threads to some very high values (-99 for the
    child thread
    and -98 for the
    main thread
    ).

  3. The
    child thread
    is doing some heavy task that is using 100% of the CPU.

  4. The
    main thread
    is trying the call printf() after the
    child thread
    is created.



The problem is that once the child thread is created, it freezes stdout and nothing gets printed on the console anymore. However, when the program exits, all the messages suddenly shown up in the console. Below is a .cpp file demonstrating this effect:

main.cpp:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>

bool EXIT = false;

void signal_handler(int signal){
EXIT = true;
}

void *child_thread(void *x_args){
printf("Setting child thread CPU affinity (Core #1)...\n");
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(1, &cpuset);
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset)){
perror("Cannot set child thread CPU affinity");
printf("Exit\n");
exit(1);
}

printf("Locking memory of child thread...\n");
mlockall(MCL_CURRENT | MCL_FUTURE);

printf("Setting child thread priority (-99)...\n");
struct sched_param sched_param;
sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
if (sched_setscheduler(0, SCHED_FIFO, &sched_param)){
perror("Cannot set child thread priority");
printf("Exit\n");
exit(1);
}

printf("Entering while loop inside child thread...\n");
while(!EXIT){}
return NULL;
}

int main(){
signal(SIGINT, signal_handler);

pthread_t thread;

printf("Setting main thread CPU affinity (Core #0)...\n");
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset)){
perror("Cannot set main thread CPU affinity");
printf("Exit.\n");
exit(1);
}

printf("Locking memory of main thread...\n");
mlockall(MCL_CURRENT | MCL_FUTURE);

printf("Setting main thread priority (-98)...\n");
struct sched_param sched_param;
sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-2;
if (sched_setscheduler(0, SCHED_FIFO, &sched_param)){
perror("Cannot set main thread priority");
printf("Exit.\n");
exit(1);
}

printf("Creating child thread...\n");
if (pthread_create(&thread, NULL, child_thread, NULL)){
perror("Cannot create child thread");
printf("Exit.\n");
exit(1);
}

printf("Entering while loop in main thread...\n");
while(!EXIT){
sleep(1);
printf("I can't see this until I press Ctrl+C!\n");
}
pthread_join(thread, NULL);

printf("Exit.\n");
return 0;
}


You can compile it with:

g++ main.cpp -pthread -o main


Then run it with:

sudo ./main


Then you should see stdout freezes after outputing the following:

Setting main thread CPU affinity (Core #0)...
Locking memory of main thread...
Setting main thread priority (-98)...
Creating child thread...
Entering while loop in main thread...
Setting child thread CPU affinity (Core #1)...


Even after an hour you just won't see anymore outputs. But when
Ctrl+C
is pressed. You will see all the messages coming out:

I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!
I can't see this until I press Ctrl+C!


The
main thread
is actually running in the background because if you comment out the two lines inside the while loop (the sleep and printf), you can see that it is also using 100% of CPU. But ht

What am I missing here?

Tav Tav
Answer

I won't claim to be an expert but you appear to have a single resource, stdout, and two threads attempting to use it. I believe printf is thread safe, but not reentrent. My fist instinct would be to use some kind of thread safe locking around the access to printf and stdout to ensure only one thread is calling it at a time.