标签: memory-model

.NET 中的后续写入是否可以由运行时或处理器重新排序?

我有不可变的对象,我希望延迟计算其哈希码。我已经实施了

private bool _HasHashCode = false;
private int _HashCode;
public override int GetHashCode()
{
    if (_HasHashCode)
        return _HashCode;

    long hashCode;
    unchecked
    {
        hashCode = Digits;
        hashCode = (hashCode*397) ^ XI;
        hashCode = (hashCode*397) ^ YI;
        hashCode = (int) ( hashCode % Int32.MaxValue);
    }

    // is it possible that these two write instructions
    // get reordered on a certain .NET/CPU architecture 
    // combination:

    _HashCode = (int)hashCode;
    _HasHashCode = true;

    return _HashCode;
}
Run Code Online (Sandbox Code Playgroud)

我的推理是,32 位 _HashCode 成员是 32 位,写入它是原子的,因此即使由于设置 _HasHashCode 属性时的竞争条件而运行两次计算也没关系 …

c# memory-model thread-safety

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

在 C++ 中,获取/释放原子访问和与栅栏结合的宽松访问之间有什么有效的区别吗?

具体来说,以下之间是否有任何有效的区别:

i = a.load(memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)

或者

a.store(5, memory_order_release);
Run Code Online (Sandbox Code Playgroud)

atomic_thread_fence(memory_order_acquire);
i = a.load(memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)

或者

a.store(5, memory_order_relaxed);
atomic_thread_fence(memory_order_release);
Run Code Online (Sandbox Code Playgroud)

分别?

非宽松原子访问是否提供信号栅栏和线程栅栏?

c++ multithreading memory-model memory-barriers stdatomic

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

此示例是否包含数据争用?

这是最初的问题,但我的问题与它有一些不同。C++ 内存模型 - 此示例是否包含数据争用?

我的问题:

//CODE-1: initially, x == 0 and y == 0
if (x) y++; // pthread 1
if (y) x++; // pthread 2
Run Code Online (Sandbox Code Playgroud)

注意:上面的代码是用 C 编写的,而不是 C++(没有内存模型)。那么它是否包含数据竞争?

从我的角度来看:如果我们在顺序一致性内存模型中查看代码,则不存在数据竞争,因为 x 和 y 永远不会同时为非零。但是,我们永远不能假设顺序一致性内存模型,因此编译器重新排序可以进行尊重线程内正确性的转换,因为编译器不知道线程的存在......对吗?

所以代码可以改写为:

//CODE-2
y++; if (!x) y--;
x++; if (!y) x--;
Run Code Online (Sandbox Code Playgroud)

上面的转换没有违反顺序正确性,所以它是正确的。这不是编译器的错,对吧?所以我同意 CODE-1 包含数据竞争的观点。你呢?

我有一个额外的问题,带有内存模型的 C++11 可以解决这个数据竞争,因为编译器知道线程,所以他们会根据内存模型类型进行重新排序,对吧?

c multithreading memory-model java-memory-model c++11

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

使用 Turbo C 编译并链接到 .com 文件

我正在尝试使用 Turbo C 编译器和链接器编译一个简单的程序并将其链接到 DOS .com 文件。我尝试了我能想到的最简单的 C 程序。

void main()
{}
Run Code Online (Sandbox Code Playgroud)

Turbo C 链接器中是否有链接到 com 文件的命令行参数?

我从链接器收到的错误消息如下:

“致命:无法生成 COM 文件:入口点地址无效”

我知道 com 文件需要入口点位于 100h。Turbo C 是否有设置此地址的选项?

linker dos memory-model turbo-c x86-16

5
推荐指数
2
解决办法
1823
查看次数

内存模型/缓存一致性协议:TSO 如何与 MESIF 结合使用

刚刚学完系统的编程讲座材料后,我偶然发现了内存模型以及缓存一致性协议的关键概念。尽管它们作为独立概念是有意义的,但尚不清楚它们如何结合在一起。具体来说,在查看 x86 时,我正在使用强制执行 TSO 内存模型的 ISA,以及使用 MESIF 缓存一致性协议的 CPU(对于 Intel)。

\n\n

一开始,教授引入了缓存一致性协议,作为确保芯片中任何核心都访问一个大的单片内存块的手段。然后,在结束了缓存一致性之后,他继续研究内存模型,特别是 TSO(我们已经在并行编程课程中介绍了线性化/顺序一致性)。以下是直接引用有关 x86 内存模型的讲座材料:

\n\n
\n
    \n
  • 64 位 x86 处理器的标准\n \n
      \n
    • 有时称为总商店订购 (TSO)
    • \n
    • 早期的 32 位 x86 实现的 PRAM \xe2\x80\x93 较弱!
    • \n
  • \n
  • 写入读取放宽:稍后的读取可以绕过早期的写入\n \n
      \n
    • 所有处理器都按照发出的顺序查看来自一个处理器的写入。
    • \n
    • 处理器可以看到来自不同处理器的不同写入交错。
    • \n
  • \n
\n
\n\n

似乎我们通过在缓存层次结构中引入(又一个)层,即(有序的)存储缓冲区,“解决”了缓慢的顺序一致性问题。\n对我来说,TSO 似乎与缓存一致性的原则正交。我们非常努力地让我们的缓存匹配,只是在两者之间添加了未被缓存一致性覆盖的另一层。

\n\n

问题:

\n\n
    \n
  1. 为什么存储缓冲区没有被缓存一致性协议覆盖?是否假设从存储缓冲区写回 L1 的速度如此之快,以至于在大多数情况下中间写回导致的不一致不会成为问题?(即我认为存储缓冲区 -> L1 传输只需要几个周期,因此一旦 L1 接收到数据,它就会通过总线发送一个事务,告诉其他核心使其副本无效)
  2. \n
  3. 我应该如何看待缓存一致性和内存模型这两个概念?按照我的理解,内存模型是我们想要的理论概念,而缓存一致性是实现所述模型的实际实现的一部分。
  4. \n
\n\n

提前非常感谢您的澄清!

\n\n

最好,\n菲利克斯

\n

architecture caching system memory-model

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

MESI 协议和 std::atomic - 它是否确保所有写入对其他线程立即可见?

关于std::atomic,C++11 标准规定,存储到原子变量将在“合理的时间内”对该变量的加载变得可见。

\n\n

从 29.3p13 开始:

\n\n
\n

实现应该使原子存储在合理的时间内对原子加载可见。

\n
\n\n

然而,我很想知道在处理基于 MESI 缓存一致性协议(x86、x86-64、ARM 等)的特定 CPU 架构时实际会发生什么。

\n\n

如果我对 MESI 协议的理解是正确的,那么一个核心总是会立即读取先前写入/正在由另一个核心写入的值,可能是通过窥探它。(因为写入值意味着发出 RFO 请求,这反过来会使其他缓存行无效)

\n\n

这是否意味着当一个线程 A 将一个值存储到 an 中时std::atomic,另一个连续对该原子进行加载的线程 B 实际上总是会观察到 A 在 MESI 架构上写入的新值?(假设没有其他线程正在对该原子执行操作)

\n\n

\xe2\x80\x9csuccessively\xe2\x80\x9d 我的意思是在线程 A 发出原子存储之后。(修改顺序已更新)

\n

c++ cpu-architecture memory-model stdatomic mesi

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

memory_order_consume 到底有什么作用?

来自链接: 加载/存储宽松原子变量和普通变量有什么区别?

这个回答给我留下了深刻的印象:

使用原子变量解决了这个问题——通过使用原子,即使内存顺序放宽,所有线程都可以保证读取最新的写入值。

今天,我阅读了以下链接:https : //preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/

atomic<int*> Guard(nullptr);
int Payload = 0;
Run Code Online (Sandbox Code Playgroud)

线程1:

  Payload = 42;
    Guard.store(&Payload, memory_order_release);
Run Code Online (Sandbox Code Playgroud)

线程2:

g = Guard.load(memory_order_consume);
if (g != nullptr)
    p = *g;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

问题: 我了解到数据依赖会阻止相关指令被重新排序。但我认为这对于确保执行结果的正确性是显而易见的。comsume-release 语义是否存在并不重要。所以我想知道 comsum-release 真的可以。哦,也许它使用数据依赖性来防止指令重新排序,同时确保 Payload 的可见性

所以

如果我使 1.preventing 指令重新排序 2.确保 Payload 的非原子变量的可见性,是否有可能使用 memory_order_relaxed 获得相同的正确结果:

atomic<int*> Guard(nullptr);
volatile int Payload = 0;   // 1.Payload is volatile now

// 2.Payload.assign and Guard.store in order for data dependency
Payload = 42;               
Guard.store(&Payload, memory_order_release);

// 3.data Dependency …
Run Code Online (Sandbox Code Playgroud)

c++ cpu-architecture memory-model lock-free stdatomic

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

Go 中的原子操作是否确保其他变量对其他线程可见?

这让我很困惑,我正在阅读 golang 内存模型,https://golang.org/ref/mem

var l sync.Mutex
var a string

func f() {
    a = "hello, world"
    l.Unlock()
}

func main() {
    l.Lock()
    go f()
    l.Lock()
    print(a)
}
Run Code Online (Sandbox Code Playgroud)

互斥锁通过原子解锁

UnLock: new := atomic.AddInt32(&m.state, -mutexLocked)

Lock: atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) 
Run Code Online (Sandbox Code Playgroud)

我的问题是,原子 AddInt32、CompareAndSwapInt32 是否会导致内存障碍,如果a在不同的 goroutine 中可见的话。

在java中,我知道AtomicInteger,内存屏障通过“易失性”,保持线程字段可见。

memory-model go memory-barriers

5
推荐指数
2
解决办法
1944
查看次数

释放+获取可以打破发生之前吗?

当今许多编程语言都具有happens-before关系和release+acquire同步操作。

\n

其中一些编程语言:

\n\n

我想知道是否release+acquire可以违反happens-before

\n
    \n
  • 如果可能的话,我想看一个例子
  • \n
  • 如果不可能,那么我想得到简单明了的解释
  • \n
\n
\n
什么是release+acquirehappens-before
\n

Release/acquire建立happens-before不同线程之间的关系:换句话说,保证releasein之前的所有内容在afterThread 1中可见:Thread 2acquire

\n
 \\     Thread 1                        /            \n  \\    --------                       /             \n   \\   x = 1                         / Everything   \n    \\  y …
Run Code Online (Sandbox Code Playgroud)

c++ java memory-model java-memory-model happens-before

5
推荐指数
2
解决办法
597
查看次数

C++中变量的修改顺序是如何定义的?

我读过这个问答:与“(简单)发生在之前”相比,“强烈发生在之前”的意义是什么?

作者给出了一个有趣的评估的概述,该评估在 C++20 之前是不可能的,但显然从 C++20 开始是可能的:

.-- T3 y.store(3, seq_cst);                   --.                 (2)
|        |                                      | strongly
|        | sequenced before                     | happens
|        V                                      | before
|   T3 a = x.load(seq_cst); // a = 0    --.   <-'                 (3)
|                                         : coherence-
|                                         : ordered
|                                         : before
|   T1 x.store(1, seq_cst);             <-'   --. --.             (4)
|        |                                      |st |
|        | sequenced before                     |h  |
|        V                                      |b  |
| . T1 y.store(1, release);                   <-'   |             (x)
| | …
Run Code Online (Sandbox Code Playgroud)

c++ memory-model stdatomic c++20

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