【发布时间】:2013-05-28 09:41:39
【问题描述】:
我正在阅读 Anthony Williams 的“C++ Concurrency in Action”和第 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;
}
这是一种未定义的行为,只是碰巧按预期运行吗?
提前致谢!
【问题讨论】:
-
你的编译器是什么(以及你的标准库的实现)?我不能让它编译器here,实际上这就是我所期待的
-
当您使用它时,我预计不会出现问题。当两个(或更多)线程试图同时修改同一个字符串时,就会出现问题。那时,
string的非平凡操作符将开始引起问题。只是在std::atomic中包装一些东西不太可能破坏没有它就可以的代码。同时,如果不遵守它的规则,它也无助于那些没有它就会被破坏的代码。 -
这几乎肯定是“偶然的”未定义行为:Microsoft 的字符串实现使用了小字符串优化,您正在测试的小字符串可以有效地轻松复制。如果您使用更长的字符串 - 以便启动堆分配 - 您应该会看到更加丰富多彩的效果。
-
你当然不会失败,你只有一个线程!如果您有多个线程访问字符串,则会发生 UB,因此修改可能不像您希望的那样“原子”。 (UB!)
-
一个普通的
std::string至少有 3 个指针大小的成员,因此在任何主流 C++ 实现中它永远不会是 lock_free。让 std::atomic 对每个访问进行锁定而不是仅仅使用你自己的互斥锁基本上是没有意义的。
标签: c++ atomic stdstring stdatomic