Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 子功能中的内存隔离与数据更改时的同一功能中的内存隔离_C++_Multithreading_Memory Fences - Fatal编程技术网

C++ 子功能中的内存隔离与数据更改时的同一功能中的内存隔离

C++ 子功能中的内存隔离与数据更改时的同一功能中的内存隔离,c++,multithreading,memory-fences,C++,Multithreading,Memory Fences,如果我在子函数中而不是在使用数据的函数中放置内存围栏,那么线程安全性是否存在差异。 下面的示例包括两个版本。我不知道是否有我不知道的差异。功能A_功能和B_功能是否同样线程安全 #include<atomic> using std::atomic; using std::atomic_thread_fence; using std::memory_order_acquire; using std::memory_order_release; typedef struct {

如果我在子函数中而不是在使用数据的函数中放置内存围栏,那么线程安全性是否存在差异。 下面的示例包括两个版本。我不知道是否有我不知道的差异。功能
A_功能
B_功能
是否同样线程安全

#include<atomic>

using std::atomic;
using std::atomic_thread_fence;
using std::memory_order_acquire;
using std::memory_order_release;

typedef struct 
{
    atomic<int> lock;
    int counter;
}Data;

void A_acquire(atomic<int> * lock);
void A_release(atomic<int> * lock);
void A_function(Data * data);
void B_acquire(atomic<int> * lock);
void B_release(atomic<int> * lock);
void B_function(Data * data);

void A_acquire(atomic<int> * lock)
{
    int ticket = lock->fetch_add(1);
    while (0 != ticket)
    {
        lock->fetch_sub(1);
        ticket = lock->fetch_add(1);
    }
    //DIFFERENCE HERE
}

void A_release(atomic<int> * lock)
{
    //DIFFERENCE HERE
    lock->fetch_sub(1);
}

void A_function(Data * data)
{
    A_acquire(&data->lock);
    atomic_thread_fence(std::memory_order_acquire); //DIFFERENCE HERE
    data->counter += 1;
    atomic_thread_fence(std::memory_order_release); //DIFFERENCE HERE
    A_release(&data->lock);
}

void B_acquire(atomic<int> * lock)
{
    int ticket = lock->fetch_add(1);
    while (0 != ticket)
    {
        lock->fetch_sub(1);
        ticket = lock->fetch_add(1);
    }
    atomic_thread_fence(std::memory_order_acquire); //DIFFERENCE HERE
}

void B_release(atomic<int> * lock)
{
    atomic_thread_fence(std::memory_order_release); //DIFFERENCE HERE
    lock->fetch_sub(1);
}

void B_function(Data * data)
{
    B_acquire(&data->lock);
    //DIFFERENCE HERE
    data->counter += 1;
    //DIFFERENCE HERE
    B_release(&data->lock);
}

int main(void)
{
    Data dat = { 0, 0 };
    A_function(&dat);
    B_function(&dat);
    return 0;
}
#包括
使用std::原子;
使用std::原子线围栏;
使用std::内存\顺序\获取;
使用std::内存\顺序\释放;
类型定义结构
{
原子锁;
整数计数器;
}数据;
无效A_获取(原子*锁);
无效A_释放(原子*锁);
无效A_函数(数据*数据);
无效B_获取(原子*锁);
无效B_释放(原子*锁);
无效B_函数(数据*数据);
无效A_获取(原子*锁)
{
int ticket=lock->fetch\u add(1);
而(0!=票)
{
锁定->获取子单元(1);
票证=锁定->提取\添加(1);
}
//这里的区别
}
无效A_释放(原子*锁)
{
//这里的区别
锁定->获取子单元(1);
}
无效A_函数(数据*数据)
{
A_获取(&数据->锁定);
原子线程围栏(std::内存顺序获取);//这里的区别
数据->计数器+=1;
原子线程围栏(std::内存顺序释放);//这里的区别
A_释放(&数据->锁定);
}
无效B_获取(原子*锁)
{
int ticket=lock->fetch\u add(1);
而(0!=票)
{
锁定->获取子单元(1);
票证=锁定->提取\添加(1);
}
原子线程围栏(std::内存顺序获取);//这里的区别
}
无效B_释放(原子*锁)
{
原子线程围栏(std::内存顺序释放);//这里的区别
锁定->获取子单元(1);
}
无效B_函数(数据*数据)
{
B_获取(和数据->锁定);
//这里的区别
数据->计数器+=1;
//这里的区别
B_释放(&数据->锁定);
}
内部主(空)
{
数据dat={0,0};
A_函数(&dat);
B_函数(&dat);
返回0;
}

从语义上讲,
A_函数
B_函数
没有区别。记忆栅栏效应不受函数体的限制

此外,正如Phantom所指出的,示例中的内存围栏是不必要的:
fetch_sub()
fetch_add()
都已经具有acquire+release语义

但通过以下修改,发布获取变得至关重要:

void A_acquire(atomic<int> * lock)
{
    int ticket = lock->exchange(1);
    while (0 != ticket)
    {
        ticket = lock->exchange(1);
    }
    //DIFFERENCE HERE
}

void A_release(atomic<int> * lock)
{
    //DIFFERENCE HERE
    lock->store(0, memory_order_relaxed);
}
void A_获取(原子*锁)
{
int票证=锁->交换(1);
而(0!=票)
{
票证=锁->交换(1);
}
//这里的区别
}
无效A_释放(原子*锁)
{
//这里的区别
锁定->存储(0,内存\u顺序\u松弛);
}

原子线程围栏之间可能会发生某种情况,这将导致数据竞争。@Phantom如果围栏位于内部而不是外部,我的获取/释放函数是否会重新排序,或者您是否指出这是一种不好的样式,因为这样围栏就不那么显眼了?哎呀,错过了互斥锁,代码应该没问题。但是,线程围栏是不必要的,因为锁定和解锁互斥已经有了获取/释放语义。