相关疑难解决方法(0)

num ++是'int num'的原子吗?

一般地,对于int num,num++(或++num),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):

在此输入图像描述

由于第5行对应于num++一条指令,我们可以得出结论,在这种情况下num++ 是原子的吗?

如果是这样,是否意味着如此生成num++可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>并强加相关成本,因为它是无论如何原子)?

UPDATE

请注意,这个问题不是增量是否原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).

c c++ assembly multithreading atomic

148
推荐指数
8
解决办法
1万
查看次数

什么时候使用volatile多线程?

如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?

那么多线程程序中volatile的用途/目的是什么?

c++ concurrency multithreading atomic volatile

121
推荐指数
3
解决办法
5万
查看次数

C++ 11 atomic <T>可用于mmap吗?

我想添加一个在Linux嵌入式系统上运行的服务(守护进程)使用的一些参数的网络控制.不需要过程调用,每个参数都可以以非常自然的方式进行轮询.共享内存似乎是一种很好的方法,可以将网络代码保留在守护程序之外,并限制对一组精心控制的变量的共享访问.

因为我不希望部分写入导致从未写过的值的可见性,所以我在考虑使用std::atomic<bool>std::atomic<int>.但是,我担心这std::atomic<T>可能会以只适用于C++ 11线程而不是多个进程的方式实现(可能,甚至不包括OS线程).具体来说,如果实现使用存储在共享内存块之外的任何数据结构,则在多进程方案中,这将失败.

我确实看到一些要求,这些要求表明std::atomic不会存在嵌入式锁定对象或指向其他数据的指针:

原子积分专业化和专业化atomic<bool>应具有标准布局.它们每个都有一个普通的默认构造函数和一个普通的析构函数.它们应各自支持聚合初始化语法.

应该有原子类模板的指针部分特化.这些特化应具有标准布局,普通默认构造函数和普通析构函数.它们应各自支持聚合初始化语法.

在我看来,无关紧要的默认构造和破坏是排除关联的每个对象数据,无论是存储在对象内,还是通过指针成员变量,还是通过外部映射.

但是,我认为没有任何东西可以排除使用单个全局互斥/临界区(或者甚至是全局集合)的实现,只要集合元素不与单个原子对象相关联 - 这与缓存关联方案一致可用于减少虚假冲突).显然,使用全局互斥锁的实现对多个进程的访问会失败,因为用户将拥有独立的互斥锁,而不是实际上彼此同步.

atomic<T>允许执行与进程间共享内存不兼容的实现,还是有其他规则使其安全?


我只是注意到,普通的默认构造使对象处于未就绪状态,并且需要调用atomic_init.标准提到了锁的初始化.如果这些存储在对象中(并且动态内存分配似乎不可能,因为析构函数仍然是微不足道的),那么它们将在进程之间共享.但我仍然担心全球互斥的可能性.

在任何情况下,保证atomic_init对共享区域中的每个变量进行单次调用似乎很难......所以我想我将不得不避开C++ 11原子类型.

c++ multithreading atomic shared-memory c++11

32
推荐指数
1
解决办法
4636
查看次数

SSE指令:哪些CPU可以进行原子16B内存操作?

考虑在x86 CPU上进行单个内存访问(单个读取或单个写入,而不是读取或写入)SSE指令.该指令访问16字节(128位)的存储器,访问的存储器位置对齐为16字节.

文档"英特尔®64架构内存订购白皮书"指出,对于"读取或写入地址在8字节边界上对齐的四字(8字节)的指令",内存操作似乎作为单个内存访问执行,而不管记忆类型.

问题:是否存在Intel/AMD/etc x86 CPU,它们保证读取或写入与16字节边界对齐的16字节(128位)作为单个内存访问执行?是这样,它是哪种特定类型的CPU(Core2/Atom/K8/Phenom/...)?如果您对此问题提供答案(是/否),请同时指定用于确定答案的方法 - PDF文档查找,强力测试,数学证明或您用于确定答案的任何其他方法.

此问题涉及http://research.swtch.com/2010/02/off-to-races.html等问题


更新:

我在C中创建了一个可以在您的计算机上运行的简单测试程序.请在您的Phenom,Athlon,Bobcat,Core2,Atom,Sandy Bridge或您碰巧拥有的任何支持SSE2的CPU上编译并运行它.谢谢.

// Compile with:
//   gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.

#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;

unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));

void* thread1(void *arg) {
        for (int i=0; i<100*1000*1000; i++) { …
Run Code Online (Sandbox Code Playgroud)

concurrency x86 sse atomic thread-safety

30
推荐指数
3
解决办法
7100
查看次数

29
推荐指数
3
解决办法
2万
查看次数

为什么在x86上对自然对齐的变量进行整数赋值?

我一直在读这篇关于原子操作的文章,它提到了32位整数赋值在x86上是原子的,只要该变量是自然对齐的.

为什么自然对齐确保原子性?

c c++ concurrency x86 atomic

28
推荐指数
2
解决办法
5386
查看次数

在实践中,无锁原子是否无地址?

Boost.Interprocess是一个很棒的库,可以简化不同进程之间共享内存的使用.它提供互斥锁,条件变量和信号量,允许在从共享内存中写入和读取时进行同步.

但是,在某些情况下,这些(相对)性能密集型同步机制不是必需的 - 原子操作足以满足我的用例,并且可能会提供更好的性能.

不幸的是,Boost.Interprocess似乎没有原子.


C++标准库提供了std::atomic类模板,它封装了操作需要是原子的对象,还具有测试原子操作是否无锁的功能.但它也不要求无锁原子也不需要地址:[atomics.lockfree]/4只是鼓励无锁操作无地址,这与cppreference一致.

我想不出为什么会以非地址方式实现无锁原子的任何理由.在我看来,以无地址的方式实现无锁原子相当容易.

因为在使用原子而不是互斥体(来自Boost.Interprocess)时我会获得显着的性能优势,所以在这里折扣标准兼容性并将std::atomic对象存储在共享内存中似乎很诱人.


这个问题分为两部分:

  1. 在实践中,CPU是否以无地址方式实现无锁原子?(我只关心用于运行现代桌面和移动操作系统的CPU(例如Windows,MacOS,Linux,Android,iOS),但不关心嵌入式系统)
  2. 为什么实现使用无锁地址的无地址原子?

c++ atomic shared-memory lock-free c++17

7
推荐指数
1
解决办法
660
查看次数

读者/写者锁...没有读者锁?

我感觉这可能是一种非常普遍和常见的情况,对此有一个众所周知的无锁解决方案。

简而言之,我希望有一种像读取器/写入器锁这样的方法,但这不需要读取器获取锁,因此可以获得更好的平均性能。

相反,对于读取器来说会有一些原子操作(128 位 CAS),对于写入器来说会有一个互斥锁。我有数据结构的两个副本,一个用于正常成功查询的只读副本,以及一个要在互斥锁保护下更新的相同副本。将数据插入可写副本后,我们将其设为新的可读副本。一旦所有待处理的读取器都读完它,旧的可读副本就会被依次插入,写入器会旋转剩余的读取器数量,直到其为零,然后依次修改它,最后释放互斥体。

或类似的东西。

存在这样的东西吗?

c++ concurrency lock-free lockless stdatomic

6
推荐指数
2
解决办法
2740
查看次数

如何用c ++ 11 CAS实现ABA计数器?

我正在实现一个基于此算法的无锁队列,该算法使用计数器来解决ABA问题.但我不知道如何用c ++ 11 CAS实现这个计数器.例如,从算法:

E9:    if CAS(&tail.ptr->next, next, <node, next.count+1>)
Run Code Online (Sandbox Code Playgroud)

它是一个原子操作,意思是如果tail.ptr->next等于next,则tail.ptr->next指向node同时(原子地)产生next.count+1.但是,使用C++ 11 CAS,我只能实现:

std::atomic_compare_exchange_weak(&tail.ptr->next, next, node);
Run Code Online (Sandbox Code Playgroud)

这不可能next.count+1同时发生.

c++ multithreading lock-free lockless c++11

5
推荐指数
1
解决办法
1924
查看次数

升级到MacPorts gcc 7.3后,is_lock_free()返回false

以前,使用Apple LLVM 9.1.0,128 is_lock_free()位结构已经恢复正常.为了得到完全的std::optional支持,我随后升级到了MacPorts gcc 7.3.在我第一次尝试编译时,我遇到了这个臭名昭着的showstopper链接器错误:

Undefined symbols for architecture x86_64:
  "___atomic_compare_exchange_16", referenced from:
Run Code Online (Sandbox Code Playgroud)

我知道我可能需要添加-latomic.使用Apple LLVM 9.1.0,我不需要它,我对此非常不满意.如果它是无锁的,您通常不需要链接到任何其他库,单独的编译器就能够处理它.否则,它可能只是基于锁的,需要来自其他库的支持.正如我所担心的那样,添加后-latomic,构建成功,但is_lock_free()返回false.

我认为gcc 7.3及其标准库实现很好.这可能只是我身上的一些配置问题.事实上,我没有做任何配置.我只是安装了MacPorts gcc并完成了.知道我可能缺少什么吗?

c++ gcc atomic lock-free gcc7

5
推荐指数
1
解决办法
272
查看次数

是否可以使用std :: atomic与POD结构,除了它有一个construtor?

我正在使用一些原子变量,所有unsigned int,我想将它们收集到一个结构中 - 实际上是一个POD.但是我也想要一个构造函数,因为我的编译器不是c ++ 11(所以我必须定义自己的构造函数来创建初始值).

所以最初我有:

// Names are not the real names - this is just for example
std::atomic<int> counter1;
std::atomic<int> counter2;
std::atomic<int> counter3;
Run Code Online (Sandbox Code Playgroud)

然后我很乐意根据需要增加/减少它们.但后来我决定再多一些计数器,因此将它们放入一个结构中:

struct my_counters {
    int counter1;
    int counter2;
    int counter3;
    // Constructor so that I can init the values I want.
    my_counters(c1, c2, c3) : counter1(c1), counter2(c2), counter3(c3){;}
};
Run Code Online (Sandbox Code Playgroud)

但是因为我添加了一个自定义构造函数,所以这在技术上不再是POD.我正在阅读有关此问题的其他问题,他们说使用std :: atomic我需要一个POD,但我读到的其他问题表明结构需要是可复制的或者一些这样的...无论如何,我感到很困惑,我想要要知道我是否可以安全地使用我的结构my_counters作为原子类型:

std::atomic<my_counters> counters;
Run Code Online (Sandbox Code Playgroud)

然后在各种线程内:

// Are these operations now still atomic (and therefore safe to use across threads):
counters.counter1++;
counters.counter2--;
counters.counter3 …
Run Code Online (Sandbox Code Playgroud)

c++ struct stdatomic

3
推荐指数
2
解决办法
1030
查看次数