scanf(), std::cin 在多线程环境中的行为如何?

Posted

技术标签:

【中文标题】scanf(), std::cin 在多线程环境中的行为如何?【英文标题】:How do scanf(), std::cin behave on multithreaded environment? 【发布时间】:2013-09-17 07:52:42 【问题描述】:

我想用一个例子来说明我的问题。

假设有一组N /*(N>>1)*/ 线程被设置为运行这个函数:

void Process() 
    //Some thread safe processing which requires in-deterministic computation time

    unsigned char byte;
    std::cin >> byte;

一旦所有这些都同时启动,会发生什么?如何处理并发 std::cin 访问?在控制台上操作的最终用户看到/体验了什么?

编辑:我还想补充一件事。下面的代码是否足够安全,可以放弃仅在一个(可能是主)线程中使用 std:cin 的想法?

void Process() 
    //Some thread safe processing which requires in-deterministic computation time

    //Mutex lock
    unsigned char byte;
    std::cin >> byte;
    //Mutex unlock

【问题讨论】:

具体来说,你不应该在多线程环境中完全避免这些函数,而应该只从一个线程调用它们。 我知道这种用法处理的安全问题。我问这个的原因是为我实现为交叉编译的 C++ 的新 SIMD 编程语言确定语法规则(是否强制程序员在主线程中使用标准输入)。 @diegoperini:假设stdin 在某种程度上是特殊的,并且存在一个实际的main thread。请记住,在 C++ 中,std::cin 并没有那么特别。这只是一个std::istream&。而且你真的不能将每个istream& 都限制在主线程中。 【参考方案1】:

我想说,如果没有互斥锁,结果是无法预测的。

如果你使用互斥体,一切都很好。这就是互斥锁的用途。

【讨论】:

【参考方案2】:

Pre C++11,取决于实现;最后一个 实现保证了调用的同步。 (VC++ 保证std::cout的同步,但不保证其他 iostream 对象。 g++ 提供与 C++11 相同的保证, 即使在早期版本的编译器中。)在 C++11 中,它是 明确未定义的行为。

一般规则很简单:任何状态的修改 任何线程中的对象都需要同步所有访问。 并且 std::istream 上的所有 >> 运算符都被认为是 修改其状态。

更一般地说,对于任何特定的流,它可能是一个很好的 策略只在一个线程中使用它。 (也有例外, 例如日志流,其中日志对象确保线程 安全性。)对于输入尤其如此,因为即使当 外部同步,运算符的排序将 如果它们在单独的线程中,通常是未指定的。所以 即使同步,如果您的用户输入"ab", 线程获取'a',在您的示例中获取'b' 将是 未定。

编辑:

标准流对象似乎有特殊规则 (std::cinstd::cout 等)。并发访问是 至少在某些情况下,保证不会产生数据竞争。 它仍然可能导致字符混合,即:如果你是 输入int(而不是单个字符),以及您的用户 输入"123 89\n",线程1有可能会看到 "1389\n" 和线程 2 "2 ",这不会让你连贯 结果。

我的全球建议不变。我想不出任何现实的 字符交错不会产生的情况 一个问题。 (另外,我想我从来没有写过这样的代码 实际上来自std::cin 的输入;它总是来自 std::istream& 可能是 std::cin,或者可能是 一个文件。)

【讨论】:

【参考方案3】:

第一个线程使用 std::cin 锁定它(除非你 use sync_with_stdio(false))。所以,你不需要互斥锁。 http://en.cppreference.com/w/cpp/io/cin 无论如何我不建议在多线程应用程序中使用它。 问题是无法中断其他线程的cin输入。

【讨论】:

已投赞成票,除非提供更多有用信息,否则将标记为最佳。 标准并没有说std::cin 锁定它;它说不会有数据竞争。这在实践中意味着什么并不太清楚,但标准确实明确表示字符可以交错。 (我想在输入字节时没问题,但在输入可能超过一个字符的任何内容时,您最终可能会出现不一致。)

以上是关于scanf(), std::cin 在多线程环境中的行为如何?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Java 在多线程环境中测试某些东西 [重复]

在多线程环境中使用 PyCurl 时程序消耗的内存不断增长

可以在多线程环境中使用单个 QueueConnection 吗?

如何在多线程环境中捕获 SIGABRT?

在多线程环境中使用 .Net UdpClient

在多线程环境中写入时的 Swift 数组复制