Pthread冻结stdout?

时间:2016-11-02 23:12:03

标签: c++ multithreading pthreads affinity thread-priority

假设在C ++程序中有两个线程(pthread):

  • main thread
  • child thread

该计划的作用很简单:

  1. 将两个线程绑定到两个不同的核心。
  2. 将两个线程的优先级设置为一些非常高的值(child thread为-99,main thread为-98)。
  3. child thread正在执行一项使用100%CPU的繁重任务。
  4. main thread在创建child thread后尝试调用printf()。
  5. 问题是,一旦创建了子线程,它就会冻结stdout,并且不再在控制台上打印任何内容。但是,当程序退出时,控制台中会突然显示所有消息。下面是一个展示这种效果的.cpp文件:

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

    你可以用:

    编译它
    g++ main.cpp -pthread -o main
    

    然后用:

    运行它
    sudo ./main
    

    然后你应该在输出以下内容后看到stdout冻结:

    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)...
    

    即使一小时后你也不会再看到输出了。但是当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!
    I can't see this until I press Ctrl+C!
    

    main thread实际上是在后台运行,因为如果你注释掉while循环中的两行(sleep和printf),你会发现它也使用了100%的CPU。但是,

    我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

我不会声称自己是专家,但您似乎只有一个资源,stdout和两个尝试使用它的线程。我相信printf是线程安全的,但不是reentrent。 我的第四个本能就是在访问printf和stdout时使用某种线程安全锁定,以确保一次只有一个线程调用它。