加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 内存障碍:工作线程如何确保初始化写入?

发布时间:2020-12-16 07:01:59 所属栏目:百科 来源:网络整理
导读:我对使用内存屏障/栅栏进行编程是相当新的,我想知道如何保证设置写入在随后在其他CPU上运行的工作器函数中可见.例如,请考虑以下事项: int setup,sheep;void SetupSheep(): // Run once CPU 1: setup = 0; ... much later CPU 1: sheep = 9; CPU 1: std::ato
我对使用内存屏障/栅栏进行编程是相当新的,我想知道如何保证设置写入在随后在其他CPU上运行的工作器函数中可见.例如,请考虑以下事项:

int setup,sheep;

void SetupSheep():    // Run once
    CPU 1: setup = 0;
    ... much later
    CPU 1: sheep = 9;
    CPU 1: std::atomic_thread_fence(std::memory_order_release);
    CPU 1: setup = 1;

之后(不是同时)运行很多次:

void ManipulateSheep():
    CPU 2: int mySetup = setup;
    CPU 2: std::atomic_thread_fence(std::memory_order_acquire);
    CPU 2: // Use sheep...

在CPU 2上,如果mySetup是1,那么羊肯定是9 – 但是我们怎样才能保证mySetup不为0?

到目前为止,我所能想到的是在CPU 2上旋转等待直到设置为1.但是这看起来非常难看,因为旋转等待只需要在第一次调用ManipulateSheep()时等待.当然必须有更好的方法吗?

请注意,未初始化代码也存在对称问题:假设您正在编写一个无锁数据结构,该结构在其生命周期内分配内存.在析构函数中(假设所有线程都已完成调用方法),您希望释放所有内存,这意味着您需要运行析构函数的CPU具有最新的变量值.在这种情况下甚至不可能旋转等待,因为析构函数无法知道“最新”状态是什么,以便检查它.

编辑:我想我要问的是:有没有办法说“等待所有商店传播到其他CPU”(用于初始化)和“等待所有商店传播到我的CPU”(用于未初始化)?

解决方法

事实证明,#StoreLoad正是这种情况的正确障碍. As explained simply by Jeff Preshing:

A StoreLoad barrier ensures that all stores performed before the barrier are visible to other processors,and that all loads performed after the barrier receive the latest value that is visible at the time of the barrier.

在C 11中,std :: atomic_thread_fence(std :: memory_order_seq_cst)显然充当#StoreLoad屏障(以及其他三个:#StoreStore,#LoadLoad和#LoadStore).见this C++11 draft paper.

附注:在x86上,mfence instruction充当#StoreLoad;如果需要,通常可以使用_mm_fence()编译器内部函数发出.

因此,无锁代码的模式可能是:

Initialize:
    CPU 1: setupStuff();
    CPU 1: std::atomic_thread_fence(std::memory_order_seq_cst);

Run parallel stuff

Uninitialize:
    CPU 2: std::atomic_thread_fence(std::memory_order_seq_cst);
    CPU 2: teardownStuff();

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读