相关疑难解决方法(0)

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

C11内存栅栏用法

即使对于一个简单的双线程通信示例,我也难以用C11原子和memory_fence样式来表达它以获得正确的内存排序:

共享数据:

volatile int flag, bucket;
Run Code Online (Sandbox Code Playgroud)

生产者线程:

while (true) {
   int value = producer_work();
   while (atomic_load_explicit(&flag, memory_order_acquire))
      ; // busy wait
   bucket = value;
   atomic_store_explicit(&flag, 1, memory_order_release);
}
Run Code Online (Sandbox Code Playgroud)

消费者线程:

while (true) {
   while (!atomic_load_explicit(&flag, memory_order_acquire))
      ; // busy wait
   int data = bucket;
   atomic_thread_fence(/* memory_order ??? */);
   atomic_store_explicit(&flag, 0, memory_order_release);
   consumer_work(data);
}
Run Code Online (Sandbox Code Playgroud)

据我所知,上面的代码可以正确地命令存储在桶中 - > flag-store - > flag-load - > load-from-bucket.但是,我认为在load-from-bucket和使用新数据重新写入桶之间仍存在竞争条件.要在读取桶之后强制执行订单,我想我需要atomic_thread_fence()在读取桶和以下atomic_store之间进行显式操作.不幸的是,似乎没有任何memory_order论据可以对前面的负载强制执行任何操作,甚至没有memory_order_seq_cst.

一个非常脏的解决方案可能是bucket在消费者线程中使用虚拟值重新分配:这与消费者只读概念相矛盾.

在较旧的C99/GCC世界中,我可以使用__sync_synchronize()我认为足够强大的传统.

什么是更好的C11风格的解决方案来同步这种所谓的反依赖?

(当然我知道我应该更好地避免这种低级编码并使用可用的更高级别的结构,但我想了解...)

c multithreading atomic memory-fences c11

12
推荐指数
1
解决办法
2481
查看次数

C++ 标准如何使用 memory_order_acquire 和 memory_order_release 防止自旋锁互斥锁中的死锁?

TL:DR:如果互斥体实现使用获取和释放操作,那么实现是否可以像通常允许的那样进行编译时重新排序,并重叠两个应该独立于不同锁的临界区?这将导致潜在的僵局。


假设互斥锁在 上实现std::atomic_flag

struct mutex
{
   void lock() 
   {
       while (lock.test_and_set(std::memory_order_acquire)) 
       {
          yield_execution();
       }
   }

   void unlock()
   {
       lock.clear(std::memory_order_release);
   }

   std::atomic_flag lock; // = ATOMIC_FLAG_INIT in pre-C++20
};
Run Code Online (Sandbox Code Playgroud)

到目前为止看起来还可以,关于使用单个这样的互斥锁:std::memory_order_releasestd::memory_order_acquire.

在这里使用std::memory_order_acquire/std::memory_order_release不应该一见钟情。它们类似于 cppreference 示例https://en.cppreference.com/w/cpp/atomic/atomic_flag

现在有两个互斥锁保护不同的变量,两个线程以不同的顺序访问它们:

mutex m1;
data  v1;

mutex m2;
data  v2;

void threadA()
{
    m1.lock();
    v1.use();
    m1.unlock();

    m2.lock();
    v2.use();
    m2.unlock();
}

void threadB()
{
    m2.lock();
    v2.use();
    m2.unlock();

    m1.lock();
    v1.use();
    m1.unlock();
}
Run Code Online (Sandbox Code Playgroud)

释放操作可以在无关的获取操作之后重新排序(无关操作 == 对不同对象的后续操作),因此执行可以转换如下:

mutex m1;
data  v1;

mutex …
Run Code Online (Sandbox Code Playgroud)

c++ memory-model spinlock language-lawyer stdatomic

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

是否会在其他线程中始终以相同顺序看到对不同线程中不同位置的两次原子写操作?

与我之前的问题类似,请考虑以下代码

-- Initially --
std::atomic<int> x{0};
std::atomic<int> y{0};

-- Thread 1 --
x.store(1, std::memory_order_release);

-- Thread 2 --
y.store(2, std::memory_order_release);

-- Thread 3 --
int r1 = x.load(std::memory_order_acquire);   // x first
int r2 = y.load(std::memory_order_acquire);

-- Thread 4 --
int r3 = y.load(std::memory_order_acquire);   // y first
int r4 = x.load(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)

怪异的结果 r1==1, r2==0,并r3==2, r4==0有可能在C ++ 11内存模型下,这种情况下?如果我要全部替换std::memory_order_acq_rel成该std::memory_order_relaxed怎么办?

在x86上,这样的结果似乎是被禁止的,请参见此SO问题,但我一般是在询问C ++ 11内存模型。

奖励问题:

我们都同意,与std::memory_order_seq_cst怪异的结果不会在C ++ 11被允许。现在,赫伯·萨特(Herb Sutter)在他著名的- …

c++ concurrency memory-model c++11 stdatomic

4
推荐指数
3
解决办法
540
查看次数

compareAndExchange 与 compareAndExchangeAcquire 有什么区别

这是 Java 库中的一个片段:

public final boolean compareAndExchangeAcquire(boolean expectedValue, boolean newValue) {
    return (int)VALUE.compareAndExchangeAcquire(this,
                                                (expectedValue ? 1 : 0),
                                                (newValue ? 1 : 0)) != 0;
}
Run Code Online (Sandbox Code Playgroud)

它来自AtomicBoolean课堂。演员怎么能int返回一个boolean

我的主要问题:compareAndExchangevs之间有什么区别compareAndExchangeAcquire


通俗地说:在申请之前xxxAcquire和之后写的语句xxxRelease可以自由重新排序xxx

在此处输入图片说明

java concurrency java-14

0
推荐指数
1
解决办法
292
查看次数