I am reading through Anthony Williams' "C++ Concurrency in Action" and in Chapter 5, which talks about the new multithreading-aware memory model and atomic operations, and he states:
我正在阅读Anthony Williams的“c++并发的作用”和第5章,其中讨论了新的多线程感知内存模型和原子操作,他说:
In order to use
std::atomic<UDT>
for some user-definedUDT
, this type must have a trivial copy assignment operator.为了对某些用户定义的UDT使用std::atomic
,该类型必须具有一个普通的复制分配操作符。
As I understand it, this means that we can use std::atomic<UDT>
if the following returns true:
正如我所理解的,这意味着我们可以使用std::原子
std::is_trivially_copyable<UDT>::value
By this logic, we shouldn't be able to use std::string
as a template argument for std::atomic
and have it work correctly.
按照这种逻辑,我们不应该使用std::string作为std::atomic的模板参数,并使其正确工作。
However, the following code compiles and runs with expected output:
但是,下面的代码编译并运行预期的输出:
#include <atomic>
#include <thread>
#include <iostream>
#include <string>
int main()
{
std::atomic<std::string> atomicString;
atomicString.store( "TestString1" );
std::cout << atomicString.load() << std::endl;
atomicString.store( "TestString2" );
std::cout << atomicString.load() << std::endl;
return 0;
}
Is this a case of undefined behaviour which just happens to behave as expected?
这是一种没有定义的行为吗?
Thanks in advance!
提前谢谢!
3 个解决方案
#1
39
The standard does not specify a specialization of std::atomic<std::string>
, so the generic template <typename T> std::atomic<T>
applies. 29.5 [atomics.types.generic] p1 states:
标准没有指定std::atomic(原子)
There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).
有一个泛型类模板原子。模板参数T的类型应该是可复制的(3.9)。
There is no statement that the implementation must diagnose violations of this requirement. So either (a) your use of std::atomic<std::string>
invokes undefined behavior, or (b) your implementation provides std::atomic<std::string>
as a conforming extension.
没有声明说实现必须诊断违反此需求的情况。因此,要么(a)使用std::原子 <:string> 调用未定义的行为,或者(b)您的实现提供std::原子 <:string> 作为一个一致性扩展。
Looking at the MSDN page for std::atomic<T>
(http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx), it does explicitly mention the requirement that T
be trivially copyable, and it does NOT say anything specific about std::atomic<std::string>
. If it is an extension, it's undocumented. My money is on undefined behavior.
查看std::atomic
Specifically, 17.6.4.8/1 applies (with thanks to Daniel Krügler for setting me straight):
具体来说,17.6.4.8/1适用(感谢Daniel Krugler为我澄清):
In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.
在某些情况下(替换函数、处理程序函数、用于实例化标准库模板组件的类型的操作),c++标准库依赖于c++程序提供的组件。如果这些组件不满足它们的需求,则该标准对实现没有要求。
std::string
certainly does not meet the std::atomic<T>
requirement that the template parameter T
be trivially copyable, so the standard places no requirements on the implementation. As a quality of implementation issue, note that static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable");
is an easy diagnostic to catch this violation.
string当然不满足std::atomic
2016-04-19 Update: I don't know when the change happened, but VS2015 Update 2 does now diagnose std::atomic<std::string>
:
2016-04-19更新:我不知道更改是什么时候发生的,但是VS2015更新2现在确实诊断了std::atomic
error C2338: atomic requires T to be trivially copyable.
#2
6
No, this is undefined behavior. Moreover, since std::string is not trivially copyable, conforming compiler should have issued "at least one diagnostic message":
不,这是未定义的行为。此外,由于std::string不是一般可复制的,符合标准的编译器应该发出“至少一个诊断消息”:
29.5 Atomic types
29.5原子类型
There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).
有一个泛型类模板原子。模板参数T的类型应该是可复制的(3.9)。
1.4 Implementation compliance
1.4实现遵从性
— If a program contains a violation of any diagnosable rule [...] a conforming implementation shall issue at least one diagnostic message.
-如程序违反任何可诊断规则[…符合要求的实现应至少发出一条诊断信息。
#3
0
Why do you think this will work 'correctly' when there are multiple threads trying to read/write the std::atomic<std::string>
?
为什么当有多个线程试图读/写std::atomic
This is C++, you are definitely allowed to shoot yourself in the foot. If you want to use a type which does not satisfy the requirements you are free to use, the compiler "may" (not will!) stop you, but you will start seeing weird/unexplainable behaviour at some point when multiple threads try to read/write the string.
这是c++,你绝对可以在脚上开枪。如果您想使用不满足您可以*使用的需求的类型,编译器“may”(不是will!)会阻止您,但是当多个线程试图读取/写入字符串时,您将开始看到奇怪的/不可解释的行为。
This requirement is for guaranteeing atomicity of reads and writes, if the object is not trivially copyable then visualize this scene: The string had "Old Value" in it. 1 Writer issues .store("New Data"), now there is another thread which issues .load() on the same variable, now without a trivially_copyable property, the reader thread can see "Nld Value" or "New Value" etc. It can't be updated atomically, hence the weird results.
这一要求是为了保证读取和写入的原子性,如果对象不是可被trivially copyable,那么就可以可视化这个场景:该字符串在其中具有“旧值”。写入器发出。store(“New Data”),现在有另一个线程在同一个变量上发出。load(),现在没有一个trially_copyable属性,读取器线程可以看到“Nld值”或“New Value”等。
Since the example you posted is a sequential code, this does not happen.
因为您发布的示例是一个顺序代码,所以不会发生这种情况。
#1
39
The standard does not specify a specialization of std::atomic<std::string>
, so the generic template <typename T> std::atomic<T>
applies. 29.5 [atomics.types.generic] p1 states:
标准没有指定std::atomic(原子)
There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).
有一个泛型类模板原子。模板参数T的类型应该是可复制的(3.9)。
There is no statement that the implementation must diagnose violations of this requirement. So either (a) your use of std::atomic<std::string>
invokes undefined behavior, or (b) your implementation provides std::atomic<std::string>
as a conforming extension.
没有声明说实现必须诊断违反此需求的情况。因此,要么(a)使用std::原子 <:string> 调用未定义的行为,或者(b)您的实现提供std::原子 <:string> 作为一个一致性扩展。
Looking at the MSDN page for std::atomic<T>
(http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx), it does explicitly mention the requirement that T
be trivially copyable, and it does NOT say anything specific about std::atomic<std::string>
. If it is an extension, it's undocumented. My money is on undefined behavior.
查看std::atomic
Specifically, 17.6.4.8/1 applies (with thanks to Daniel Krügler for setting me straight):
具体来说,17.6.4.8/1适用(感谢Daniel Krugler为我澄清):
In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.
在某些情况下(替换函数、处理程序函数、用于实例化标准库模板组件的类型的操作),c++标准库依赖于c++程序提供的组件。如果这些组件不满足它们的需求,则该标准对实现没有要求。
std::string
certainly does not meet the std::atomic<T>
requirement that the template parameter T
be trivially copyable, so the standard places no requirements on the implementation. As a quality of implementation issue, note that static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable");
is an easy diagnostic to catch this violation.
string当然不满足std::atomic
2016-04-19 Update: I don't know when the change happened, but VS2015 Update 2 does now diagnose std::atomic<std::string>
:
2016-04-19更新:我不知道更改是什么时候发生的,但是VS2015更新2现在确实诊断了std::atomic
error C2338: atomic requires T to be trivially copyable.
#2
6
No, this is undefined behavior. Moreover, since std::string is not trivially copyable, conforming compiler should have issued "at least one diagnostic message":
不,这是未定义的行为。此外,由于std::string不是一般可复制的,符合标准的编译器应该发出“至少一个诊断消息”:
29.5 Atomic types
29.5原子类型
There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9).
有一个泛型类模板原子。模板参数T的类型应该是可复制的(3.9)。
1.4 Implementation compliance
1.4实现遵从性
— If a program contains a violation of any diagnosable rule [...] a conforming implementation shall issue at least one diagnostic message.
-如程序违反任何可诊断规则[…符合要求的实现应至少发出一条诊断信息。
#3
0
Why do you think this will work 'correctly' when there are multiple threads trying to read/write the std::atomic<std::string>
?
为什么当有多个线程试图读/写std::atomic
This is C++, you are definitely allowed to shoot yourself in the foot. If you want to use a type which does not satisfy the requirements you are free to use, the compiler "may" (not will!) stop you, but you will start seeing weird/unexplainable behaviour at some point when multiple threads try to read/write the string.
这是c++,你绝对可以在脚上开枪。如果您想使用不满足您可以*使用的需求的类型,编译器“may”(不是will!)会阻止您,但是当多个线程试图读取/写入字符串时,您将开始看到奇怪的/不可解释的行为。
This requirement is for guaranteeing atomicity of reads and writes, if the object is not trivially copyable then visualize this scene: The string had "Old Value" in it. 1 Writer issues .store("New Data"), now there is another thread which issues .load() on the same variable, now without a trivially_copyable property, the reader thread can see "Nld Value" or "New Value" etc. It can't be updated atomically, hence the weird results.
这一要求是为了保证读取和写入的原子性,如果对象不是可被trivially copyable,那么就可以可视化这个场景:该字符串在其中具有“旧值”。写入器发出。store(“New Data”),现在有另一个线程在同一个变量上发出。load(),现在没有一个trially_copyable属性,读取器线程可以看到“Nld值”或“New Value”等。
Since the example you posted is a sequential code, this does not happen.
因为您发布的示例是一个顺序代码,所以不会发生这种情况。