简体   繁体   English

C ++线程安全摘要

[英]C++ Thread Safety Summary

I would like a summary of what exactly is thread safe in C++ both according to the current standard and C++0x as well as in practice (generally speaking, but also in my case with gcc 4.5.1). 我想根据当前标准和C ++ 0x以及实际情况(一般来说,在我的情况下使用gcc 4.5.1)总结C ++中的线程安全。

For STL containers, my understanding is that thread safety is not guaranteed according to the current standard. 对于STL容器,我的理解是根据当前标准不保证线程安全。 Is it true though that in practice they are thread safe for single writer, multiple reader usage (on gcc and probably most modern compilers)? 虽然在实践中它们对于单个作者,多个读者使用(在gcc和可能是大多数现代编译器上)是线程安全的,但这是真的吗? Is this guaranteed by C++11?. 这是由C ++ 11保证的吗?

What about POD types? POD类型怎么样? I know that the standard guarantees nothing, but I've been told that in practice, all are thread safe for reading and writing. 我知道标准没有任何保证,但我被告知在实践中,所有这些都是线程安全的读写。 Of course even something simple like the increment operator may still need synchronization since there could be multiple reads and writes. 当然,即使是像增量运算符那样简单的东西仍然需要同步,因为可能存在多次读取和写入。

I'm primarily interested in the answers, but the why behind the answers would be appreciated to. 我主要对答案感兴趣,但是为什么答案背后的原因会受到赞赏。

None of the things you have mentioned are thread safe, either by the standard or in practice. 您提到的所有内容都不是线程安全的,无论是标准还是实践。

The reason that the standards do not mandate thread safety is that thread safety comes with an inherent cost. 标准不强制要求线程安全的原因是线程安全带来固有成本。 In general, C++ tries not to give you things that you don't ask for. 一般来说,C ++试图不向你提供你不需要的东西。 If you want thread safety, then you have to build it yourself. 如果你想要线程安全,那么你必须自己构建它。 This is true even in C++ 0x, which includes various synchronization primitives. 即使在包含各种同步原语的C ++ 0x中也是如此。

The reasons that these things are not thread safe in practice are varied. 这些东西在实践中不是线程安全的原因是多种多样的。 Generally, the STL containers are not thread safe because each of their basic update operations take multiple steps to accomplish. 通常,STL容器不是线程安全的,因为它们的每个基本更新操作都需要多个步骤来完成。 If a thread tries to read or update a container while another thread is in the process of updating it, the container will be in an indeterminate state, and thus the results will be unpredictable. 如果一个线程在另一个线程正在更新它时尝试读取或更新容器,则容器将处于不确定状态,因此结果将是不可预测的。

In the case of POD types, reads and writes can also take multiple steps to complete. 在POD类型的情况下,读取和写入也可以采取多个步骤来完成。 This simplest example is a 64-bit integer on a 32-bit machine. 这个最简单的例子是32位机器上的64位整数。 It takes at least two instructions to either read or set the value. 至少需要两条指令来读取或设置值。 Once again, this means that if a thread tries to read or update the value while another thread is in the process of updating it, the results will be unpredictable. 再一次,这意味着如果一个线程试图读取或更新该值而另一个线程正在更新它,则结果将是不可预测的。

The current standard doesn't mention threading at all, in any respect. 目前的标准在任何方面都没有提到线程。 In practice, the standard containers provide thread-safe reading, but require synchronization for writing. 实际上,标准容器提供了线程安全的读取,但需要同步进行写入。

C++ 0x doesn't talk much (at all?) specifically about containers with respect to thread safety/sharing, but does talk about assignments and such. C ++ 0x对于线程安全/共享方面的容器没有多少谈论(根本没有?),但确实讨论了赋值等。 In the end, it comes out pretty much the same though -- even though the object is in a container, you're reading/writing data, and you have to synchronize when/if at least one thread may modify the data. 最后,它几乎完全相同 - 即使对象在容器中,您正在读/写数据,并且当/如果至少一个线程可能修改数据时您必须同步。

POD data doesn't really change much: modifications will require synchronization as a general rule. POD数据并没有太大变化:修改需要同步作为一般规则。 There's usually some subset of data types for which operations are normally atomic, but the members of that subset vary by platform. 通常有一些数据类型的子集,其操作通常是原子的,但该子集的成员因平台而异。 It'll typically include types up to the native word size of the hardware allocated with "natural" alignment; 它通常包括直到用“自然”对齐分配的硬件的本机字大小的类型; anything else is open to a lot more question. 其他任何事情都可以提出更多问题。

POD and Standard defined types do not have any thread safety. POD和标准定义的类型没有任何线程安全性。 It is entirely up to the code user to synchronize their threads to ensure that nothing bad happens. 完全取决于代码用户同步其线程以确保不会发生任何不良事件。

In C++0x, I have little idea; 在C ++ 0x中,我不知道; not really checking up on that area of the Standard. 没有真正检查标准的那个区域。

Neither C nor C++ have concurrency primitives built into the language in the way (say) java has with synchronised . C和C ++都没有内置到语言中的并发原语(例如)java with synchronised This is (I believe) deliberate - even on modern versions - to avoid having the overhead when it is not needed. 这是(我相信)故意 - 即使在现代版本 - 以避免在不需要时有开销。 Unix did not support lightweight processes in the early days, so threading was largely a kernel issue. Unix在早期并不支持轻量级进程,因此线程主要是内核问题。

Various proprietary thread libraries (eg Solaris threads) were produced by vendors, and the industry ultimately standardised on the pthread library, initially with a purely userspace threading model (blocking calls like I/O would block all threads) and later with kernel thread support. 各种专有线程库(例如Solaris线程)由供应商生成,并且业界最终在pthread库上进行了标准化,最初使用纯粹的用户空间线程模型(阻塞I / O等调用会阻塞所有线程)以及稍后的内核线程支持。 Windows, OS/2 and various other operating systems offered proprietary thread facilities. Windows,OS / 2和各种其他操作系统提供专有的线程功能。

C/C++ are designed to run on systems that may or may not have thread support, and to run efficiently - so thread support is an optional extra. C / C ++被设计为在可能有或没有线程支持的系统上运行,并且可以高效运行 - 因此线程支持是一个可选的附加功能。 One of the design philosophies of C++ is that the programmer should not have to pay for features they don't use. C ++的设计理念之一是程序员不应该为他们不使用的功能付费。 One could argue the merits of this approach in an era of multi core machines but assuming 'the entire world is a PC' has been considered a major pitfall in writing portable C code for some decades now. 人们可以在多核机器的时代争论这种方法的优点,但假设“整个世界都是PC” ,几十年来一直被认为是编写便携式C代码的一个主要缺陷。

The net effect is that threading tends to be platform specific, although cross-platform threading libraries do exist. 尽管存在跨平台的线程库,但最终结果是线程往往是特定于平台的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM