fgets()是否会锁定stdout以防止printf输出?

4

我有一个C程序,其中有两个线程。其中一个线程几乎一直在使用fgets()等待用户输入。第二个线程可能需要在第一个线程在fgets()上被阻塞时打印到终端。

从我的测试中看来,程序似乎会等待第一个线程的fgets()返回,然后第二个线程才能打印。

这是正常工作方式还是我可以在另一个线程被fgets()阻塞时打印?

此实现运行于eCos(嵌入式可配置操作系统)。

线程锁定在fgets()

int my_getline (char** argv, int argvsize)
{
    static char line[MAX_LINE];
    char *p;
    int argc;

    fgets(line, MAX_LINE, stdin);


    for (argc=0,p=line; (*line != '\0') && (argc < argvsize); p=NULL,argc++) {
        p = strtok(p, " \t\n");
        argv[argc] = p;
        if (p == NULL) return argc;
    }
    argv[argc] = p;
    return argc;
}

尝试打印的线程:

while(1){
        unsigned char bufr[50];
        read_until(bufr);
        if (bufr[1] == (unsigned char)NMFL ){
            cyg_mutex_lock(&scree_mtx);
            printf("Memory half full!\n");
            cyg_mutex_unlock(&scree_mtx);
            continue;
        }
        cyg_mbox_put( mbx_serial_userH, bufr );     
}

输出(我确定消息之前已经在那里):

输出


1
你的输出是否以\n结尾?stdout是行缓冲的,因此只有在打印换行符时才会刷新。 - Barmar
经过修改,这个问题变得没有意义。所显示的输出似乎与添加的源代码无关。 - R.. GitHub STOP HELPING ICE
1
我想表达的是 - 从那些代码片段和输出片段中很难看出你是如何得出它被阻止尝试输出的结论的。你能提供更接近 最小化测试用例 的东西吗? - Oliver Charlesworth
抱歉,但是cyg_mutex_lock更有可能是锁定的候选者,而不是printf。您需要按照如何创建一个最小化、完整且可验证的示例的指南发布。请编辑问题并包含这样的示例代码。 - Luis Colorado
问题已经解决了,与线程优先级和eCos调度程序的奇怪方式有关。更改优先级并添加一些信号量解决了它。关于这个例子,这是一个读取器复杂软件,这就是为什么一开始的问题没有包含示例的原因。 - Sebastião
显示剩余12条评论
1个回答

2
C标准并未指定标准输入流和标准输出流之间的任何关联。特别地,它没有规定一个线程阻塞在从标准输入读取时(通过任何标准函数),是否应该导致任何输出函数阻塞。
然而,标准也没有说相反的话,即阻塞在从stdin输入的线程不得导致另一个线程阻塞在向stdout输出。这是否发生取决于C实现,可能还取决于与stdin和stdout相关联的特定设备。
您似乎正在使用将stdin和stdout都连接到CMD.EXE窗口的Windows C实现。Windows有很多怪癖,我倾向于猜测您观察到的阻塞是其中之一。我不会期望在Linux或OSX上看到相同的情况,但这并不意味着它是错误的。

实际上,这是针对嵌入式可配置操作系统eCos的一种实现方式,可能会出现这种情况,这就是eCos的工作方式... - Sebastião
2
这似乎并没有真正回答问题。这更像是对C标准的评论,实际上表明这种观察到的行为不是C标准所要求的,可能与操作系统的底层I/O子系统实现或C I/O库实现I/O功能的方式有关。从这份文档中可以看出,eCos的C库至少有两个配置,可以是线程安全的或非线程安全的。http://ecos.sourceware.org/docs-latest/user-guide/sample-twothreads.html 但线程安全的行为尚不清楚。 - Richard Chambers
我认为标准并没有默认允许在抽象机器可以前进的情况下不允许前进。它确实对请求输入时刷新输出流做出了一些(过时且有害的)允许,如果实现选择采取该允许,则会产生令人讨厌的死锁影响,我最初认为这与此问题有关,但经过进一步考虑,似乎并非如此。 - R.. GitHub STOP HELPING ICE
1
@RichardChambers,在我回答完这个问题后,问题被编辑为指定了eCos,显然是作为回应。原始版本是一个不具体的“它是这样工作的吗?”,对此,“这取决于,C本身并没有指定”是我们能够做出的最贴切的回应了。 - John Bollinger
@JohnBollinger,从发布的问题中缺失的信息太多了,以至于无法提供一个合理的好答案。eCos似乎有一个相当标准的过山车专有和开源历史,由于它是嵌入式的,可能涉及到硬件相关的考虑。在发布的问题中没有提到上下文/环境。例如,这是一个模拟器吗?这不是一个好问题,因为它缺少很多东西,包括一个最小和可验证的程序。任何答案都只是在等待问题被重新制定为更可接受的标准之前随意猜测。 - Richard Chambers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接