内存模型排序和可见性? [英] Memory model ordering and visibility?

查看:178
本文介绍了内存模型排序和可见性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图寻找这方面的细节,我甚至阅读关于互斥和原子的标准...但仍然我不能理解C ++ 11内存模型可见性保证。
从我理解互斥BESIDE互斥的非常重要的特性是确保可见性。也就是说,仅仅一个线程每次增加计数器是不够的,重要的是线程增加了最后使用互斥量的线程存储的计数器(我真的不知道为什么人们不提这更多在讨论时互斥,也许我有坏老师:))。
所以从我可以告诉原子不强制立即可见性:
(来自维护boost :: thread并已实现c ++ 11线程和互斥库的人):

I tried looking for details on this, I even read the standard on mutexes and atomics... but still I couldnt understand the C++11 memory model visibility guarantees. From what I understand the very important feature of mutex BESIDE mutual exclusion is ensuring visibility. Aka it is not enough that only one thread per time is increasing the counter, it is important that the thread increases the counter that was stored by the thread that was last using the mutex(I really dont know why people dont mention this more when discussing mutexes, maybe I had bad teachers :)). So from what I can tell atomic doesnt enforce immediate visibility: (from the person that maintains boost::thread and has implemented c++11 thread and mutex library):


具有memory_order_seq_cst的围栏不强制立即
对其他线程的可见性(也不是MFENCE指令)。
C ++ 0x内存排序约束只是---排序
约束。 memory_order_seq_cst操作形成一个总订单,但
没有对什么是该订单的限制,除非它必须
由所有线程同意,并且它不能违反其他顺序
约束。特别地,线程可以继续看到陈旧值
一段时间,只要它们以与
约束一致的顺序看到值。

A fence with memory_order_seq_cst does not enforce immediate visibility to other threads (and neither does an MFENCE instruction). The C++0x memory ordering constraints are just that --- ordering constraints. memory_order_seq_cst operations form a total order, but there are no restrictions on what that order is, except that it must be agreed on by all threads, and it must not violate other ordering constraints. In particular, threads may continue to see "stale" values for some time, provided they see values in an order consistent with the constraints.

我也没关系。但问题是我很难理解C ++ 11关于原子的构造是全局,并且只确保原子变量的一致性。
特别是我理解下面的内存排序(如果有的话)保证在加载和存储之前和之后会有一个内存围栏:
http://www.stdthread.co.uk/doc/headers/atomic/memory_order.html

And I'm OK with that. But the problem is that I have trouble understanding what C++11 constructs regarding atomic are "global" and which only ensure consistency on atomic variables. In particular I have understanding which(if any) of the following memory orderings guarantee that there will be a memory fence before and after load and stores: http://www.stdthread.co.uk/doc/headers/atomic/memory_order.html

从我可以告诉std :: memory_order_seq_cst插入mem屏障,而其他只强制操作在某些内存位置的顺序。

From what I can tell std::memory_order_seq_cst inserts mem barrier while other only enforce ordering of the operations on certain memory location.

因此,有人可以清除这一点,我猜想很多人会使用std :: atomic,esp如果他们不使用默认(std ::内存排序)

2.如果我是对的,这意味着第二行是冗余的代码:

So can somebody clear this up, I presume a lot of people are gonna be making horrible bugs using std::atomic , esp if they dont use default (std::memory_order_seq_cst memory ordering)
2. if I'm right does that mean that second line is redundand in this code:

atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);  

3。 do std :: atomic_thread_fences与互斥体有同样的要求,为了保证非原子变量的seq一致性,必须做std :: atomic_thread_fence(std :: memory_order_seq_cst);
之前加载和
std :: atomic_thread_fence(std :: memory_order_seq_cst);

存储后?

4.是

3. do std::atomic_thread_fences have same requirements as mutexes in a sense that to ensure seq consistency on nonatomic vars one must do std::atomic_thread_fence(std::memory_order_seq_cst); before load and std::atomic_thread_fence(std::memory_order_seq_cst);
after stores?
4. Is

  {
    regularSum+=atomicVar.load();
    regularVar1++;
    regularVar2++;
    }
    //...
    {
    regularVar1++;
    regularVar2++;
    atomicVar.store(74656);
  }

等效于

std::mutex mtx;
{
   std::unique_lock<std::mutex> ul(mtx);
   sum+=nowRegularVar;
   regularVar++;
   regularVar2++;
}
//..
{
   std::unique_lock<std::mutex> ul(mtx);
    regularVar1++;
    regularVar2++;
    nowRegularVar=(74656);
}

我想没有,但我想确定。

I think not, but I would like to be sure.

编辑:
5.
可以声明火?

只有两个主题。

5. Can assert fire?
Only two threads exist.

atomic<int*> p=nullptr; 

第一个线程写入

{
    nonatomic_p=(int*) malloc(16*1024*sizeof(int));
    for(int i=0;i<16*1024;++i)
    nonatomic_p[i]=42;
    p=nonatomic;
}

第二个线程

{
    while (p==nullptr)
    {
    }
    assert(p[1234]==42);//1234-random idx in array
}


推荐答案

如果你喜欢处理栅栏,那么 a.load(memory_order_acquire)相当于 a.load(memory_order_relaxed)后跟 atomic_thread_fence(memory_order_acquire)。类似地, a.store(x,memory_order_release)相当于调用 atomic_thread_fence(memory_order_release) a.store(x,memory_order_relaxed) memory_order_consume memory_order_acquire 的特殊情况,仅用于依赖数据 memory_order_seq_cst 是特殊的,在所有 memory_order_seq_cst 操作中形成总订单。与其他混合,它与一个加载的获取和一个商店的发布相同。 memory_order_acq_rel 用于读 - 修改 - 写操作,并且等效于RMW的读部分上的获取和写部分的释放。

If you like to deal with fences, then a.load(memory_order_acquire) is equivalent to a.load(memory_order_relaxed) followed by atomic_thread_fence(memory_order_acquire). Similarly, a.store(x,memory_order_release) is equivalent to a call to atomic_thread_fence(memory_order_release) before a call to a.store(x,memory_order_relaxed). memory_order_consume is a special case of memory_order_acquire, for dependent data only. memory_order_seq_cst is special, and forms a total order across all memory_order_seq_cst operations. Mixed with the others it is the same as an acquire for a load, and a release for a store. memory_order_acq_rel is for read-modify-write operations, and is equivalent to an acquire on the read part and a release on the write part of the RMW.

根据硬件架构,对原子操作使用排序约束可能会或可能不会导致实际的fence指令。在某些情况下,如果将排序约束放在原子操作上而不使用单独的栅栏,编译器将生成更好的代码。

The use of ordering constraints on atomic operations may or may not result in actual fence instructions, depending on the hardware architecture. In some cases the compiler will generate better code if you put the ordering constraint on the atomic operation rather than using a separate fence.

在x86上,加载总是获取,商店总是释放。 memory_order_seq_cst 需要使用 MFENCE 指令或 LOCK 前缀指令(这里有一个实现选择是否使存储具有更强的排序或负载)。因此,独立的获取和释放栅栏是空操作,但 atomic_thread_fence(memory_order_seq_cst)不是(再次需要 MFENCE LOCK ed指令)。

On x86, loads are always acquire, and stores are always release. memory_order_seq_cst requires stronger ordering with either an MFENCE instruction or a LOCK prefixed instruction (there is an implementation choice here as to whether to make the store have the stronger ordering or the load). Consequently, standalone acquire and release fences are no-ops, but atomic_thread_fence(memory_order_seq_cst) is not (again requiring an MFENCE or LOCKed instruction).

顺序约束的一个重要影响是, / strong>操作。

An important effect of the ordering constraints is that they order other operations.

std::atomic<bool> ready(false);
int i=0;

void thread_1()
{
    i=42;
    ready.store(true,memory_order_release);
}

void thread_2()
{
    while(!ready.load(memory_order_acquire)) std::this_thread::yield();
    assert(i==42);
}

thread_2 它从 ready 中读取 true 。由于 thread_1 中的准备的存储是发布,并且加载是获取,则存储同步-with 加载,以及 i 发生之前 i 在assert,并且assert将不会触发。

thread_2 spins until it reads true from ready. Since the store to ready in thread_1 is a release, and the load is an acquire then the store synchronizes-with the load, and the store to i happens-before the load from i in the assert, and the assert will not fire.

2)

atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);  

确实潜在多余,因为 atomicVar 默认使用 memory_order_seq_cst 。然而,如果在这个线程上还有其他非 - memory_order_seq_cst 原子操作,那么fence会有后果。例如,它将作为后续 a.store(x,memory_order_relaxed)的释放栅栏。

is indeed potentially redundant, because the store to atomicVar uses memory_order_seq_cst by default. However, if there are other non-memory_order_seq_cst atomic operations on this thread then the fence may have consequences. For example, it would act as a release fence for a subsequent a.store(x,memory_order_relaxed).

3)栅栏和原子操作不像互斥体那样工作。你可以使用它们来构建互斥体,但它们不像他们一样工作。你不必使用 atomic_thread_fence(memory_order_seq_cst)。没有要求任何原子操作 memory_order_seq_cst ,并且可以实现非原子变量的排序,如上例所示。

3) Fences and atomic operations do not work like mutexes. You can use them to build mutexes, but they do not work like them. You do not have to ever use atomic_thread_fence(memory_order_seq_cst). There is no requirement that any atomic operations are memory_order_seq_cst, and ordering on non-atomic variables can be achieved without, as in the example above.

4)没有这些不是等价的。因此,没有互斥锁的代码段是一个数据竞争和未定义的行为。

4) No these are not equivalent. Your snippet without the mutex lock is thus a data race and undefined behaviour.

5)没有你的断言无法触发。使用memory_order_seq_cst的默认存储器排序,来自原子指针 p 的存储和加载类似于上面的示例中的存储和加载,并且保证数组元素的存储发生在读取之前。

5) No your assert cannot fire. With the default memory ordering of memory_order_seq_cst, the store and load from the atomic pointer p work like the store and load in my example above, and the stores to the array elements are guaranteed to happen-before the reads.

这篇关于内存模型排序和可见性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆