在C++多线程中,cout和printf有什么区别?

5
一些背景: 我有一个使用pthread的C++程序,是一个酒店预订系统,有10个客人(每个客人都有自己的线程),一个办理入住手续的前台(1个线程)和一个退房前台(1个线程)。酒店只有5个客房可以供客人使用。在这个程序中,我使用信号量来实现互斥和事件排序。
问题: 这是我代码的一部分:(仅展示必要的部分...)
sem_init(&openRooms, 0, 5);

sem_wait(&openRooms);   //waits for there to be an open room at the hotel

cout << "Guest " << guestNumber << " waits for check-in." << endl;

sem_wait(&checkInLine); //waits for an open spot at the check-in desk

一次只能有5位客人入住酒店,因为只有5间房间。当我运行程序时,会得到以下输出(或类似内容):

Guest Guest Guest Guest 24 waits for check-in. waits for check-in.1 waits for check-in. 
3 waits for check-in.

看起来cout允许多个打印同时运行,这就是为什么“Guest”会连续多次打印的原因。

我尝试使用printf做同样的事情,但不会出现相同的问题。在另一个线程可以打印语句之前,整个语句已经被打印了。

sem_wait(&checkInSt); //Only one person at check in receptionist at a time
printf("Guest %ld goes to the check-in receptionist.\n", my_rank);
currentThreadIn = my_rank; //Rank for receptionist to use in room assignment

输出:

Guest 1 waits for check in.
Guest 3 waits for check in.
Guest 2 waits for check in.
Guest 4 waits for check in.
Guest 0 waits for check in.

为什么会发生这种情况?cout是否使用了某种bugger?此外,是否有任何方法可以使用cout来避免这种情况?我可以使用额外的信号量来确保cout语句在另一个语句之前打印,但我正在寻找一种不使用额外信号量的方法。


请参考以下链接:https://dev59.com/MGrWa4cB1Zd3GeqP-Fxo - NPE
2个回答

14
printf("Guest %ld goes to the check-in receptionist.\n", my_rank);

当你使用 printf 时,你的字符串会被格式化到一个内部缓冲区中,然后在单个操作中输出到控制台(例如:"Guest 2 waits for check-in.")。

cout << "Guest " << guestNumber << " waits for check-in." << endl;
当您使用cout时,您的字符串会分多个部分输出到控制台 - "Guest",接着是guestNumber,然后是" waits for check-in.",最后是endl。这是因为每次调用<<运算符时,它都像是一个单独的函数调用(返回对同一cout对象的引用供下一次调用使用)。
因此,尽管向控制台写入本身是线程安全且原子的,但在cout情况下,每个单独的子字符串只是原子的。
如果您不想使用printf,解决方案将是a)使用信号量或其他锁定机制,或b)在打印之前使用stringstream格式化文本,然后将其作为单个字符串输出。

太棒了!感谢你解释所有的工作原理。我最终只是将所有内容更改为printf()语句。效果非常好! - hatz

1
我发现了相同的结果。Printf 总是有效的。我认为除非你加锁,否则没有办法使 cout “线程安全”。如果你必须使用流来处理字符串,请考虑以下代码:
ss << "Hello World! Thread ID, " << tid << endl;
printf("%s",ss.str().c_str());

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