相关疑难解决方法(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万
查看次数

获取/发布与顺序一致的内存顺序

对于std::atomic<T>T是基本类型的任何地方:

如果我使用std::memory_order_acq_relfetch_xxx操作,以及std::memory_order_acquire用于load操作和std::memory_order_releasestore操作盲目(我的意思是,就像重置这些功能的默认内存排序)

  • 结果是否与我使用std::memory_order_seq_cst(用作默认值)的任何声明操作相同?
  • 如果结果相同,那么这种用法std::memory_order_seq_cst在效率方面是否与使用不同?

c++ concurrency atomic c++11

36
推荐指数
2
解决办法
8122
查看次数

C++ 11 memory_order_acquire和memory_order_release语义?

http://en.cppreference.com/w/cpp/atomic/memory_order和其他C++ 11在线参考,将memory_order_acquire和memory_order_release定义为:

  • 获取操作:在此加载之前,不能对当前线程中的读取进行重新排序.
  • 释放操作:在此存储之后,当前线程中的写入不能重新排序.

这似乎允许在获取操作之前执行获取后写入,这看起来很奇怪(通常的获取/释放操作语义限制所有内存操作的移动).

相同的在线资源(http://en.cppreference.com/w/cpp/atomic/atomic_flag)表明可以使用C++原子和上面提到的宽松内存排序规则构建自旋锁互斥:

lock mutex: while (lock.test_and_set(std::memory_order_acquire))

unlock mutex: lock.clear(std::memory_order_release);               
Run Code Online (Sandbox Code Playgroud)

有了这个锁定/解锁的定义,如果确实以这种方式定义了memory_order_acquire/release,那么下面的简单代码就不会被破坏(即,不禁止对获取后写入进行重新排序):

Thread1:
  (0) lock
    (1) x = 1;
    (2) if (x != 1) PANIC
  (3) unlock

Thread2:
  (4) lock
    (5) x = 0;
  (6) unlock
Run Code Online (Sandbox Code Playgroud)

以下执行是否可行:(0)锁定,(1)x = 1,(5)x = 0,(2)PANIC?我错过了什么?

c++ multithreading memory-model c++11

25
推荐指数
1
解决办法
8294
查看次数

使用4个线程获取/释放语义

我目前正在阅读Anthony Williams的C++ Concurrency in Action.他的一个列表显示了这段代码,他声明z != 0可以解雇的断言.

#include <atomic>
#include <thread>
#include <assert.h>

std::atomic<bool> x,y;
std::atomic<int> z;

void write_x()
{
    x.store(true,std::memory_order_release);
}

void write_y()
{
    y.store(true,std::memory_order_release);
}

void read_x_then_y()
{
    while(!x.load(std::memory_order_acquire));
    if(y.load(std::memory_order_acquire))
        ++z;
}

void read_y_then_x()
{
    while(!y.load(std::memory_order_acquire));
    if(x.load(std::memory_order_acquire))
        ++z;
}

int main()
{
    x=false;
    y=false;
    z=0;
    std::thread a(write_x);
    std::thread b(write_y);
    std::thread c(read_x_then_y);
    std::thread d(read_y_then_x);
    a.join();
    b.join();
    c.join();
    d.join();
    assert(z.load()!=0);
}
Run Code Online (Sandbox Code Playgroud)

所以我能想到的不同执行路径是这样的:

1)

Thread a (x is now true)
Thread c (fails to increment z)
Thread b (y …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading memory-model memory-barriers stdatomic

19
推荐指数
2
解决办法
851
查看次数

C++内存模型中的哪些确切规则会阻止在获取操作之前重新排序?

我在以下代码中有关于操作顺序的问题:

std::atomic<int> x;
std::atomic<int> y;
int r1;
int r2;
void thread1() {
  y.exchange(1, std::memory_order_acq_rel);
  r1 = x.load(std::memory_order_relaxed);
}
void thread2() {
  x.exchange(1, std::memory_order_acq_rel);
  r2 = y.load(std::memory_order_relaxed);
}
Run Code Online (Sandbox Code Playgroud)

鉴于std::memory_order_acquirecppreference页面上的描述(https://en.cppreference.com/w/cpp/atomic/memory_order),

具有此内存顺序的加载操作会对受影响的内存位置执行获取操作:在此加载之前,不能对当前线程中的读取或写入进行重新排序.

很明显,r1 == 0 && r2 == 0在跑步thread1thread2同时之后永远不会有结果.

但是,我在C++标准中找不到任何措辞(现在查看C++ 14草案),这保证了两个宽松的加载不能与获取 - 释放交换重新排序.我错过了什么?

编辑:正如评论中所建议的那样,实际上可以使r1和r2都等于零.我已经更新了程序以使用load-acquire,如下所示:

std::atomic<int> x;
std::atomic<int> y;
int r1;
int r2;
void thread1() {
  y.exchange(1, std::memory_order_acq_rel);
  r1 = x.load(std::memory_order_acquire);
}
void thread2() {
  x.exchange(1, std::memory_order_acq_rel);
  r2 = y.load(std::memory_order_acquire);
}
Run Code Online (Sandbox Code Playgroud)

现在是有可能得到两个和r1以及 …

c++ atomic memory-barriers language-lawyer stdatomic

18
推荐指数
2
解决办法
780
查看次数

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

在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
查看次数

"后续读取"在volatile变量的上下文中意味着什么?

Java 内存可见性文档说:

在每次后续读取同一字段之前,会发生对易失性字段的写入.

我很困惑多线程背景下的后续意义.这句话是否意味着所有处理器和内核都有一些全局时钟.那么例如我在某个线程的循环c1中为变量赋值,然后第二个线程能够在后续循环c1 + 1中看到该值?

java multithreading cpu-architecture

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

如何在 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
查看次数

"存储缓冲区转发"在英特尔开发人员手册中的含义是什么?

英特尔64和IA-32架构软件开发人员手册说,大约由单一处理器的行动("在P6更多最近的处理器系列内存排序和"第8.2.2节)重新排序如下:

读取可以使用较旧的写入到不同位置进行重新排序,但不能使用较旧的写入到同一位置.

接下来讨论与早期处理器相比放松的点时,它说:

存储缓冲区转发,当读取将写入传递到同一存储器位置时.

据我所知,"存储缓冲区转发"并未在任何地方精确定义(也不是"通过").读取将写入传递到同一位置是什么意思,因为上面说它不能通过写入同一位置来重新排序?

concurrency assembly intel cpu-architecture memory-model

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