多线程程序上的printf函数

时间:2017-12-20 19:10:28

标签: c multithreading

我在c中编写一个简单的程序,该程序有两个线程和两个全局变量,但printf函数不起作用,我知道printf不是线程安全的,如果我很好的话在打印中添加\ n它会起作用,但是我不明白为什么没有它就无法工作? 我正在添加代码,

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

int i;
int j;

void* runi(void* _temp)
{
    while(1)
    {
        i++;
        if(i==1000)
        {
            printf("i: %d",i);
        }
    }
    return NULL;
}

void* runj(void* _temp)
{
    while(1)
    {
        j++;
        if(j==1000)
        {
            printf("j: %d",j);
        }
    }
    return NULL;
}
main ()
{
    pthread_t threadI,threadJ;
    pthread_create(&threadI,NULL,runi,NULL);
    pthread_create(&threadJ,NULL,runj,NULL);
    pthread_join(threadI,NULL);
    pthread_join(threadJ,NULL);
    return 0;
}

1 个答案:

答案 0 :(得分:3)

printf在某种程度上是线程安全的 * (参见unlocked_stdio(3)中的讨论......,并考虑flockfile(3))但是stdio是缓冲的,你应该调用fflush(3)在你的日常生活中。

printf可能是线程安全的,因为两个并发的printf可能不会混合它们的输出,但没有任何关于刷新缓冲区的信息)

所以代码

    if(i==1000) {
        printf("i: %d",i);
        fflush(stdout);
    }

(然后你会看到一些输出)

顺便说一句,我建议您使用换行符printf结束大多数\n格式控制字符串....您还可以通过执行nanosleep(2)或{{3}来添加一些延迟在你的runi&amp; runj例程。

usleep(3)解释说你很失望。出于效率原因,应缓存stdout(请参阅buffering ...)。请注意,系统调用(在setvbuf(3)中列出的Linux)(例如syscalls(2))是非常昂贵的操作。在Linux上使用write(2)来了解已完成的系统调用。

如果您想了解Linux上printf的实现,请研究C标准库的源代码 - strace(1)。它可能是GNU free software,但可能是glibc等其他东西。

顺便说一下,你的主题永远不会结束(因为runirunj永远不会返回),你pthread_join就是这样。那个电话无限期地阻止着。使用musl-libc来观察。

您还可以考虑在第一个sleep(2); fflush(stdout);之前的main中添加一些pthread_join;然后你会观察一些输出。

最后,对于这样的实验,我建议定期打印。将i==1000条件替换为i%10000 == 0 ....

你永远不会明确刷新你的stdout,以便当它的缓冲区(可能是8K字节)已满时,或者在main)到达时,它会被刷新你的情况)。 ltrace(1)巧妙地评论说你可能需要等待一个小时才能完成(缓冲区满状态)。

谨防Jonathan Lefflerrace conditions