标签: memory-model

Java中的Peterson算法?

是否存在用于Java中互斥的Peterson算法的示例实现?

java algorithm concurrency memory-model thread-safety

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

由 if (false) 保护的数据竞争...标准是怎么说的?

考虑以下情况

// Global
int x = 0; // not atomic

// Thread 1
x = 1;

// Thread 2
if (false)
    x = 2;
Run Code Online (Sandbox Code Playgroud)

根据标准,这是否构成数据竞争?[intro.races] 说:

如果两个表达式求值之一修改内存位置 (4.4),而另一个表达式求值读取或修改同一内存位置,则两个表达式求值会发生冲突。

如果程序的执行包含两个潜在并发冲突的操作,并且至少其中一个操作不是原子操作,并且两者都发生在另一个操作之前,则该程序的执行将包含数据争用,除了下面描述的信号处理程序的特殊情况之外。任何此类数据竞争都会导致未定义的行为。

从语言律师的角度来看是否安全,因为程序永远不能执行“表达式求值” x = 2;

从技术角度来看,如果某个奇怪、愚蠢的编译器决定对该写入执行推测执行,并在检查实际情况后将其回滚,该怎么办?

激发这个问题的原因是(至少在标准 11 中),允许以下程序的结果完全取决于重新排序/推测执行:

// Thread 1:
r1 = y.load(std::memory_order_relaxed);
if (r1 == 42) x.store(r1, std::memory_order_relaxed);
// Thread 2:
r2 = x.load(std::memory_order_relaxed);
if (r2 == 42) y.store(42, std::memory_order_relaxed);
// This is allowed to result in r1==r2==42 in c++11
Run Code Online (Sandbox Code Playgroud)

(比较https://en.cppreference.com/w/cpp/atomic/memory_order

c++ concurrency memory-model language-lawyer

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

Java内存模型(JSR-133)是否意味着进入监视器会刷新CPU数据缓存?

有一些东西让我对Java内存模型感到困扰(如果我甚至正确理解了所有内容).如果有两个线程A和B,则无法保证B将看到A写入的值,除非A和B在同一监视器上同步.

对于保证线程之间的高速缓存一致性的任何系统体系结构,没有问题.但是,如果架构不支持硬件中的缓存一致性,这实质上意味着每当线程进入监视器时,之前所做的所有内存更改都必须提交到主内存,并且缓存必须无效.它需要是整个数据缓存,而不仅仅是几行,因为监视器没有信息,它在内存中保存哪些变量.但这肯定会影响任何需要频繁同步的应用程序的性能(特别是像短时间运行的作业队列这样的事情).那么Java可以在没有硬件缓存一致性的架构上合理地工作吗?如果没有,为什么内存模型不能提供更强的可见性保证?如果语言需要监视器保护的信息,那会不会更有效率?

正如我所看到的,内存模型给我们带来了两个世界中最糟糕的,绝对需要同步,即使硬件中保证了高速缓存一致性,另一方面,非相干体系结构上的性能不佳(完全高速缓存刷新).因此,它不应该更严格(需要信息由监视器保护)或更多地丢失和限制缓存一致的架构的潜在平台?

就像现在一样,它对我来说没有多大意义.有人可以清楚为什么选择这种特定的记忆模型吗?


编辑:回想起来,我对严格和失败的使用是一个糟糕的选择.我对"保证较少"的情况使用"严格",而对相反则"丢失".为了避免混淆,最好用更强或更弱的保证来说话.

java multithreading synchronization memory-model cpu-cache

17
推荐指数
2
解决办法
1121
查看次数

为什么将memory_order作为std :: atomic函数的运行时参数给出

std::atomic功能,诸如storeload采取一个std::memory_order参数.可以在运行时确定参数,就像任何其他函数参数一样.但是,实际值可能会影响编译期间代码的优化.考虑以下:

std::atomic<int> ai1, ai2;
int value = whatever;

void foo() {
    std::memory_order memOrd = getMemoryOrder();
    register int v = value; // load value from memory
    ai1.store(v, memOrd);   // dependency on v's value
    ai2.store(1, memOrd);   // no dependency. could this be move up?
}
Run Code Online (Sandbox Code Playgroud)

如果memOrd碰巧memory_order_relaxed,第二个商店可以安全地移动到第一个商店前面.这将在加载value和使用它之间增加一些额外的工作,这可能会阻止其他需要的停顿.但是,如果memOrdmemory_order_seq_cst,则不应该允许切换存储,因为如果设置为1 ai1,value则某些其他线程可能指望已经设置为ai2.

我想知道为什么内存顺序被定义为运行时参数而不是编译时间.在决定最佳内存操作语义之前,有人在运行时检查环境是否有任何理由?

c++ atomic memory-model c++11

17
推荐指数
1
解决办法
566
查看次数

C++ 11内存模型并在不同的线程中访问同一结构的不同成员

假设您有以下定义:

struct X
{
  char a, b;
};

X x;
Run Code Online (Sandbox Code Playgroud)

现在假设您有两个线程,其中一个读取和写入x.a但从不访问,x.b而另一个读取和写入x.b但从不访问x.a.两个线程都不使用任何锁或其他同步原语.这可以保证在C++ 11中有效吗?或者它是否算作访问同一个对象,因此需要锁定?

c++ multithreading memory-model thread-safety c++11

17
推荐指数
1
解决办法
726
查看次数

什么是C++ 11标准中的使用操作?

我已经看到这个关于获取,释放,消费等的问题存在,但是,没有答案真正定义了"消费操作"实际上是什么.

在1.10第5段中,它指出:

在一个或多个存储器位置上的同步操作是消费操作,获取操作,释放操作,或获取和释放操作两者.

我想知道是否有人可以解释这是什么,因为它在C++ 11标准的1.10部分中使用?

c++ multithreading memory-model c++11 semantics

15
推荐指数
1
解决办法
2413
查看次数

为什么标准C#事件调用模式是线程安全的,没有内存屏障或缓存失效?类似的代码怎么样?

在C#中,这是以线程安全方式调用事件的标准代码:

var handler = SomethingHappened;
if(handler != null)
    handler(this, e);
Run Code Online (Sandbox Code Playgroud)

其中,可能在另一个线程上,编译器生成的add方法用于Delegate.Combine创建新的多播委托实例,然后在编译器生成的字段上设置该实例(使用互锁比较交换).

(注意:出于这个问题的目的,我们不关心在事件订阅者中运行的代码.假设它在删除时是线程安全且健壮的.)


在我自己的代码中,我想按照以下方式做类似的事情:

var localFoo = this.memberFoo;
if(localFoo != null)
    localFoo.Bar(localFoo.baz);
Run Code Online (Sandbox Code Playgroud)

哪里this.memberFoo可以由另一个线程设置.(这只是一个线程,所以我不认为它需要联锁 - 但也许这里有副作用?)

(并且,显然,假设它Foo是"不可变的",我们在这个线程上使用它时不会主动修改它.)


现在我理解这是线程安全的明显原因:从引用字段读取是原子的.复制到本地可确保我们不会获得两个不同的值.(显然只能从.NET 2.0保证,但我认为它在任何理智的.NET实现中都是安全的吗?)


但我不明白的是:被引用的对象实例所占用的内存如何?特别是在缓存一致性方面?如果"writer"线程在一个CPU上执行此操作:

thing.memberFoo = new Foo(1234);
Run Code Online (Sandbox Code Playgroud)

什么保证Foo分配新内存的内存不会出现在"读取器"运行的CPU的缓存中,具有未初始化的值?什么确保localFoo.baz(上面)不读取垃圾?(跨平台的保证有多好?在Mono上?在ARM上?)

如果新创建的foo恰好来自游泳池呢?

thing.memberFoo = FooPool.Get().Reset(1234);
Run Code Online (Sandbox Code Playgroud)

从内存的角度来看,这似乎没有什么不同,只是一个新的分配 - 但是.NET分配器可能会让第一个案例有效吗?


在我提出这个问题时,我的想法是需要一个内存屏障来确保 - 不是因为读取依赖而不能移动内存访问 - 而是作为CPU的一个信号来清除任何缓存失效.

我的来源是维基百科,所以你要做的就是这样.

(我可能会猜测,也许在连动比较交换作家线程上无效缓存读者?或者,也许所有的读取原因失效吗?或者指针引用引起失效?我特别关注如何平台特有的这些东西的声音.)


更新:只是为了更明确地说明问题是关于CPU缓存失效以及.NET提供的保证(以及这些保证可能如何依赖于CPU架构):

  • 假设我们在字段Q(内存位置)中存储了引用.
  • 上CPU (作家)我们在初始化存储器位置的对象R …

c# memory-model thread-safety memory-barriers mesi

15
推荐指数
1
解决办法
667
查看次数

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

java:带有getter和setter的`volatile`私有字段

我们应该声明私有字段,就像volatile在多个线程中使用instanced一样吗?

Effective Java中,有一个例子,代码在没有volatile的情况下不起作用:

import java.util.concurrent.TimeUnit;

// Broken! - How long would you expect this program to run?
public class StopThread {
    private static boolean stopRequested; // works, if volatile is here

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested)
                    i++;
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

解释说

while(!stopRequested)
    i++;
Run Code Online (Sandbox Code Playgroud)

优化到这样的事情:

if(!stopRequested)
    while(true)
        i++;
Run Code Online (Sandbox Code Playgroud)

所以stopRequested后台线程看不到进一步的修改,所以它永远循环.(顺便说一句,该代码在没有 …

java volatile memory-model java-memory-model

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

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

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