std :: atomic <std :: string>是否正常工作?</std :: string>

时间:2013-06-01 19:25:54

标签: c++ c++11 atomic standard-library

我正在阅读Anthony Williams的“行动中的C ++并发”和第5章,其中讨论了新的多线程感知内存模型和原子操作,并指出:

  

为了对某些用户定义的std::atomic<UDT>使用UDT,此类型必须具有普通复制赋值运算符。

据我了解,这意味着如果以下内容返回true,我们可以使用std::atomic<UDT>

std::is_trivially_copyable<UDT>::value

按照这种逻辑,我们不应该使用std::string作为std::atomic的模板参数,并使其正常工作。

但是,以下代码使用预期输出编译并运行:

#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;
}

这是一个未定义行为的情况,恰好按预期行事吗?

提前致谢!

3 个答案:

答案 0 :(得分:41)

标准未指定std::atomic<std::string>的专精,因此适用通用template <typename T> std::atomic<T>。 29.5 [atomics.types.generic] p1陈述:

  

有一个泛型类模板atomic。模板参数T的类型应该是可以轻易复制的(3.9)。

没有声明该实施必须诊断违反此要求的行为。因此,(a)您使用std::atomic<std::string>调用未定义的行为,或(b)您的实现提供std::atomic<std::string>作为符合标准的扩展。

查看std::atomic<T>http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx)的MSDN页面,它确实明确提到T可以轻易复制的要求,并且没有说明std::atomic<std::string>的具体内容}。如果它是扩展名,则没有记录。我的钱是未定义的行为。

具体来说,17.6.4.8/1适用(with thanks to Daniel Krügler for setting me straight):

  

在某些情况下(替换函数,处理函数,用于实例化标准库模板组件的类型的操作),C ++标准库依赖于C ++程序提供的组件。如果这些组件不符合要求,则标准对实施没有要求。

std::string当然不符合模板参数std::atomic<T>可以轻易复制的T要求,因此标准对实现没有要求。作为实施质量问题,请注意static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable");是一种易于诊断以捕获此违规行为的问题。


2016-04-19更新:我不知道更改何时发生,但VS2015 Update 2现在确诊std::atomic<std::string>

error C2338: atomic requires T to be trivially copyable.

答案 1 :(得分:6)

不,这是未定义的行为。此外,由于std :: string不是易于复制的,因此符合标准的编译器应该发出“至少一条诊断消息”:

  

29.5原子类型

     

有一个泛型类模板atomic。模板参数T的类型应该是可以轻易复制的(3.9)。

     

1.4实施合规性

     

- 如果某个程序包含违反任何可诊断规则[...]符合规定的内容   实施应至少发出一条诊断信息。

答案 2 :(得分:0)

为什么你认为这会正常运作&#39;当有多个线程试图读/写std::atomic<std::string>

这是C ++,你绝对可以用脚射击自己。如果您想使用不满足您可以使用的要求的类型,编译器可以&#34;可能&#34; (不会!)阻止你,但是当多个线程尝试读/写字符串时,你会在某个时刻开始看到奇怪/无法解释的行为。

此要求用于保证读取和写入的原子性,如果对象不是可轻易复制的,则可视化此场景:字符串具有旧值&#34;在里面。 1 Writer问题.store(&#34; New Data&#34;),现在有另一个线程在同一个变量上发出.load(),现在没有trivially_copyable属性,读者线程可以看到&#34; Nld Value& #34;或者&#34;新价值&#34;它不能原子地更新,因此结果很奇怪。

由于您发布的示例是顺序代码,因此不会发生这种情况。