标签: stdatomic

显式原子加载/存储和通常的运算符=和运​​算符T之间有什么区别?

考虑以下两种变体:

std::atomic<int> a;
a = 1;
int b = a;
Run Code Online (Sandbox Code Playgroud)

std::atomic<int> a;
a.store(1);
int b = a.load();
Run Code Online (Sandbox Code Playgroud)

我从文档中看到第二个是完全原子的,但我不明白何时应该使用哪个以及什么是细节上的差异.

c++ c++11 stdatomic

16
推荐指数
1
解决办法
2157
查看次数

Atomic shared_ptr用于无锁单链表

我想知道是否有可能为任何"常见"架构(如x64或ARMv7/ARMv8)创建无锁,线程安全的共享指针.

cppcon2014上关于无锁编程的讨论中,Herb Sutter提出了一个无锁定单链表的(部分)实现.实现看起来很简单,但它依赖于shared_ptr标准库中不存在或使用专用std::atomic...函数的原子实现.这一点尤为重要,因为单个push/pop调用可能会调用多个原子加载/存储和compare_exchange操作.

我看到的问题(我认为谈话中的一些问题是朝着相同的方向)是因为这是一个实际的无锁数据结构,那些原子操作本身就必须是无锁的.我不知道任何标准库实现std::atomic...的无锁功能 - 至少有一个简短的google/SO搜索 - 我也没有找到如何实现无锁专业化的建议std::atomic<std::shared_ptr>.

在我浪费时间之前,我想问:

  • 你知道吗,如果有可能写一个无锁的原子共享指针呢?
  • 是否已经有任何我忽略的实现 - 理想情况 - 甚至与您期望的实现兼容std::atomic<std::shared_ptr>?对于所提到的队列,它尤其需要CAS操作.
  • 如果无法在当前体系结构上实现此功能,那么与锁定保护的"普通"链接列表相比,您是否看到Herb实现中的任何其他好处?

供参考,这里是来自Herb Sutter的代码(可能包含来自我的错别字):

template<class T> 
class slist {
    struct Node { T t;  std::shared_ptr<Node> next; };
    std::atomic<std::shared_ptr<Node>> head;        
public:
    class reference{
        std::shared_ptr<Node> p;
    public:
        reference(std::shared_ptr<Node> p_){}
        T& operator*(){ return p->t; }
        T* operator->(){ return &p->t; }
    };
    auto find(T t) const {
        auto p = head.load();
        while …
Run Code Online (Sandbox Code Playgroud)

c++ lock-free shared-ptr data-structures stdatomic

16
推荐指数
2
解决办法
4138
查看次数

memory_order_consume和memory_order_acquire之间的区别

我有一个关于GCC-Wiki文章的问题.在标题"总结"下,给出了以下代码示例:

线程1:

y.store (20);
x.store (10);
Run Code Online (Sandbox Code Playgroud)

线程2:

if (x.load() == 10) {
  assert (y.load() == 20)
  y.store (10)
}
Run Code Online (Sandbox Code Playgroud)

据说,如果释放所有商店并获得所有负载,则线程2中的断言不会失败.这对我来说很清楚(因为线程1中x的存储与线程2中x的加载同步).

但现在出现了我不理解的部分.还有人说,如果所有商店都被释放并且消耗了所有负载,那么结果是相同的.来自y的负载是否可能在x的负载之前被提升(因为这些变量之间没有依赖关系)?这意味着线程2中的断言实际上可能会失败.

c c++ atomic memory-model stdatomic

15
推荐指数
2
解决办法
1834
查看次数

在没有互斥体的情况下在C++ 11中实现共享整数计数器的最简单方法:

假设我们有以下代码来计算出现事件的次数:

int i=0;
void f() {
   // do stuff  . . .
   if(something_happens) ++i;
}

int main() {
    std::vector<std::thread> threads;
    for(int j = 0; j< std::thread::hardware_concurrency(); ++j) {
        threads.push_back(std::thread(f));
    }

    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread_join));
    std::cout << "i = " << i << '\n';
}
Run Code Online (Sandbox Code Playgroud)

目前看来我的竞争条件很明显.使用C++ 11,什么是(1)消除这种竞争条件的最简单方法,以及(2)最快的方法?,最好不使用互斥锁.谢谢.

更新:使用注释使用原子,我得到了一个工作程序,编译在英特尔编译器,版本13:

#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
#include <algorithm>

std::atomic<unsigned long long> i = 0;

void f(int j) {
    if(j%2==0) {
        ++i;
    }  
}

int main() {
    std::cout << "Atomic i = " …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading c++11 stdatomic

14
推荐指数
1
解决办法
1675
查看次数

其他线程是否会以相同的顺序看到两个对不同线程中相同位置的轻松写入?

在x86架构上,存储到同一内存位置的总订单有,例如,请参阅此视频.C++ 11内存模型有哪些保证?

更确切地说,在

-- Initially --
std::atomic<int> x{0};

-- Thread 1 --
x.store(1, std::memory_order_release);

-- Thread 2 --
x.store(2, std::memory_order_release);

-- Thread 3 --
int r1 = x.load(std::memory_order_acquire);
int r2 = x.load(std::memory_order_acquire);

-- Thread 4 --
int r3 = x.load(std::memory_order_acquire);
int r4 = x.load(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)

结果r1==1, r2==2, r3==2, r4==1是否允许(在x86以外的某些架构上)?如果我要更换所有memory_order的东西std::memory_order_relaxed怎么办?

c++ concurrency memory-model c++11 stdatomic

14
推荐指数
2
解决办法
358
查看次数

如何在 C++11 中实现 StoreLoad 屏障?

我想编写可移植代码(Intel、ARM、PowerPC...)来解决一个经典问题的变体:

Initially: X=Y=0

Thread A:
  X=1
  if(!Y){ do something }
Thread B:
  Y=1
  if(!X){ do something }
Run Code Online (Sandbox Code Playgroud)

其中目标是避免两个线程都在做的情况something。(如果两者都没有运行也没关系;这不是只运行一次的机制。)如果您发现我下面的推理中有一些缺陷,请纠正我。

我知道,我可以通过memory_order_seq_cstatomic stores 和loads实现目标,如下所示:

std::atomic<int> x{0},y{0};
void thread_a(){
  x.store(1);
  if(!y.load()) foo();
}
void thread_b(){
  y.store(1);
  if(!x.load()) bar();
}
Run Code Online (Sandbox Code Playgroud)

这实现了目标,因为
{x.store(1), y.store(1), y.load(), x.load()}事件必须有一些单一的总顺序,它必须与程序顺序“边缘”一致:

  • x.store(1) “在TO之前” y.load()
  • y.store(1) “在TO之前” x.load()

如果foo()被调用,那么我们有额外的优势:

  • y.load() “之前读取值” y.store(1)

如果bar()被调用,那么我们有额外的优势:

  • x.load() “之前读取值” x.store(1)

所有这些边组合在一起将形成一个循环:

x.store(1)“在TO之前”“在TO之前y.load()读取值” y.store(1)“在TO之前” x.load()“读取之前值”x.store(true)

这违反了订单没有周期的事实。

我故意使用非标准术语“在 TO …

c++ atomic memory-barriers language-lawyer stdatomic

13
推荐指数
1
解决办法
1003
查看次数

C++20:标准如何保证atomic::wait()的返回?

这是一个语言律师问题。

\n

首先,a.wait()下面的代码是否总是返回?

\n
std::atomic_int a{ 0 };\n\nvoid f()\n{\n    a.store(1, std::memory_order_relaxed);\n    a.notify_one();\n}\nint main()\n{\n    std::thread thread(f);\n\n    a.wait(0, std::memory_order_relaxed);//always return?\n\n    thread.join();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我相信标准的目的是a.wait()总是得到回报。(否则atomic::wait/notify就没用了,不是吗?)但我认为目前的标准文本不能保证这一点。

\n

标准的相关部分位于 \xc2\xa731.6 [atomics.wait] 第 4 段:

\n
\n

对原子对象上的原子等待操作的调用M可以通过调用原子通知操作来解除阻塞M,如果存在副作用X,并且Y满足M以下条件:

\n
    \n
  • (4.1) \xe2\x80\x94 观察结果后,原子等待操作已阻塞X
  • \n
  • (4.2) \xe2\x80\x94在,的修改顺序X之前YM
  • \n
  • (4.3) \xe2\x80\x94Y发生在调用原子通知操作之前。
  • \n
\n
\n

和 \xc2\xa731.8.2 [atomics.types.operations] 第 29~33 段:

\n
\n

void wait(T …

c++ atomic language-lawyer stdatomic c++20

13
推荐指数
1
解决办法
1341
查看次数

如果使用“memory_order_relaxed”检查,为什么要使用“memory_order_seq_cst”设置停止标志?

Herb Sutter 在他的“原子<>武器”演讲中展示了原子的几个示例用途,其中之一可归结为以下内容:(视频链接,带时间戳)

  • 一个主线程启动多个工作线程。

  • 工人检查停止标志:

    while (!stop.load(std::memory_order_relaxed))
    {
        // Do stuff.
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 主线程最终执行此操作stop = true;(注意,使用 order= seq_cst),然后加入工作线程。

Sutter 解释说,使用 order= 检查标志relaxed是可以的,因为谁在乎线程是否会因稍大的延迟而停止。

但为什么要stop = true;在主线程中使用呢seq_cst?幻灯片上说这是故意不这样做relaxed,但没有解释原因

看起来它会起作用,可能会有更大的停止延迟。

这是性能和其他线程看到标志的速度之间的折衷吗?即,由于主线程仅设置标志一次,我们不妨使用最强的排序,以尽快传达消息?

c++ concurrency stdatomic

13
推荐指数
1
解决办法
710
查看次数

为什么g ++仍然需要-latomic

29.5原型类型的C++标准2014年11月的工作草案中,它指出:

  1. 有一个泛型类模板atomic.模板参数T的类型应该是可以轻易复制的(3.9).[注意:不能静态初始化的类型参数可能难以使用. - 尾注]

所以 - 据我所知 - 这:

#include <atomic>

struct Message {
    unsigned long int a;
    unsigned long int b;
};

std::atomic<Message> sharedState;

int main() {    
    Message tmp{1,2};       
    sharedState.store(tmp);         
    Message tmp2=sharedState.load();
}
Run Code Online (Sandbox Code Playgroud)

应该是完全有效的标准c ++ 14(以及c ++ 11)代码.但是,如果我没有libatomic手动链接,那么命令

g++ -std=c++14 <filename>
Run Code Online (Sandbox Code Playgroud)

给出 - 至少在Fedora 22(gcc 5.1)上 - 以下链接错误:

/tmp/ccdiWWQi.o: In function `std::atomic<Message>::store(Message, std::memory_order)':
main.cpp:(.text._ZNSt6atomicI7MessageE5storeES0_St12memory_order[_ZNSt6atomicI7MessageE5storeES0_St12memory_order]+0x3f): undefined reference to `__atomic_store_16'
/tmp/ccdiWWQi.o: In function `std::atomic<Message>::load(std::memory_order) const':
main.cpp:(.text._ZNKSt6atomicI7MessageE4loadESt12memory_order[_ZNKSt6atomicI7MessageE4loadESt12memory_order]+0x1c): undefined reference to `__atomic_load_16'
collect2: error: ld returned 1 exit status …
Run Code Online (Sandbox Code Playgroud)

c++ g++ libstdc++ c++11 stdatomic

12
推荐指数
1
解决办法
3658
查看次数

std::atomic 和 std::condition_variable 等待、notify_* 方法的区别

我正在浏览“原子操作库”,并遇到了原子“等待”和“notify_ ”方法的新 C++20 功能我很好奇 std::condition_variable 的 'wait' 和 'notify_ ' 方法有何不同

c++ condition-variable stdatomic c++20

12
推荐指数
2
解决办法
952
查看次数