2016-11-02 60 views
1

比方说,有是在C两个线程(并行线程)++程序:Pthread冻结标准输出?

  • main thread
  • child thread

什么程序做很简单:

  1. 绑定两个线程到两个不同的核心。
  2. 将两个线程的优先级设置为非常高的值(child thread为-99,main thread为-98)。
  3. child thread正在执行一些使用100%CPU的繁重任务。
  4. 在创建child thread之后,main thread正在尝试调用printf()。

问题是,一旦创建了子线程,它将冻结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; 
} 

你可以编译:

sudo ./main 

g++ main.cpp -pthread -o 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循环(睡眠和printf)内的两条线,你可以看到,它也使用100%的CPU。但是ht

我在这里错过了什么?

+0

可悲的是我不能重现这个问题。 – johnchen902

+0

@ johnchen902也许这是操作系统相关的?我正在使用Ubuntu14.04-LTS。如果未设置线程优先级,则问题不会显示。例如,如果我没有'sudo'运行它,一切正常。 – hhy

+0

问题解决了。在Tav的答案下看到我的评论。 – hhy

回答

1

我不会声称是专家,但你似乎有一个资源,标准输出和两个线程试图使用它。我相信printf是线程安全的,但不是重复的。 我的拳头本能是在对printf和stdout的访问周围使用某种线程安全锁定,以确保一次只有一个线程正在调用它。

+0

其实你是一个专家!如果我在子线程中注释掉所有'printf',问题就会消失。如果在while循环之前调用printf,则猜测子线程中的while循环会阻止其他线程访问stdout。 – hhy

+0

@hhy - 注释掉子线程中的'printf'不应该影响结果。如果子线程在'printf'返回*之后在'stdout' *上持有一个锁,那么我会考虑这个实现中的一个错误。 –