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::cin
、std::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 在多线程环境中的行为如何?的主要内容,如果未能解决你的问题,请参考以下文章