Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.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++ std::atomic_标志不提供加载或存储操作有什么缺点吗?(旋转锁示例)_C++_C++11_Atomic_Stdatomic - Fatal编程技术网

C++ std::atomic_标志不提供加载或存储操作有什么缺点吗?(旋转锁示例)

C++ std::atomic_标志不提供加载或存储操作有什么缺点吗?(旋转锁示例),c++,c++11,atomic,stdatomic,C++,C++11,Atomic,Stdatomic,与std::atomic_bool(aka)相比,在我看来std::atomic_标志只是有一个更简单的接口。它只提供测试+设置和清除标志,而std::atomic_bool也为多个运算符提供重载 我的一个问题是关于术语:“加载或存储操作”是什么意思?这是否意味着不可能任意读取和修改std::atomic_flag的值 此外,我想知道,当用于自旋锁时,std::atomic_bool能更快吗?在我看来,std::atomic_标志在自旋锁期间始终必须读写: while (my_atomic_fl

std::atomic_bool
(aka)相比,在我看来
std::atomic_标志
只是有一个更简单的接口。它只提供测试+设置和清除标志,而
std::atomic_bool
也为多个运算符提供重载

我的一个问题是关于术语:“加载或存储操作”是什么意思?这是否意味着不可能任意读取和修改
std::atomic_flag
的值

此外,我想知道,当用于自旋锁时,
std::atomic_bool
能更快吗?在我看来,
std::atomic_标志
在自旋锁期间始终必须读写:

while (my_atomic_flag.test_and_set()); // spin-lock
std::atomic_bool
只需执行读取操作(假设原子bool实现为无锁):

std::atomic_标志
是否比
std::atomic_标志
的效率更高,或者它也可能是另一种方式?旋转锁应该使用什么

什么是“加载或存储操作”?这是否意味着无法任意读取和修改std::atomic_标志的值

std::atomic_标志
不支持正常的存储/加载操作
它是一个仅修改的类型;也就是说,如果不执行修改操作,就无法读取访问
std::atomic_flag
对象。
一般来说,
std::atomic_flag
是用于其他操作的构建块。它的界面非常简单;它是唯一保证原子无锁操作的原子类型。 它支持的操作包括:

std::atomic_flag::clear()
std::atomic_flag::test_and_set()
这样,您就可以轻松构建自己的自旋锁(尽管通常不推荐):

此外,我想知道,当用于自旋锁时,std::atomic_bool会更快吗?在我看来,std::atomic_标志在自旋锁期间总是必须读写

问题是,自旋锁在获取锁时总是要修改它的状态。你不能不告诉别人就拿了锁。
基于
std::atomic
lock()
实现看起来非常相似:

while (flag.exchange(true)); 
基于
std::atomic_标志的自旋锁是否更快?

在我的平台上,编译器为这两种类型发出相同的程序集,所以我会非常惊讶不实现自旋锁,
while(my_atomic_flag.test_和_set())是的。啊,你是对的。。。我发布的不是一个旋转锁,而是一个旋转等待(因为我在当前的项目中使用了它)。一个线程必须等待另一个线程完成某些操作。因此,我想,这更像是一种信号量类型的用例。好吧,您可以使用双重检查锁定来实现自旋锁,这种锁定在大多数情况下只执行加载操作,而不是RMW,RMW是
std::atomic_flag
的唯一选项。它会产生很大的差异吗?我对此表示怀疑,但仍然如此。@ixSci:我的理解是,通常您希望以只读方式旋转,直到看到可用的锁,然后尝试使用它。然后缓存线可以在所有等待的线程中处于“共享”状态,而不是让它们都充斥着失效请求,以独占地拥有缓存线并将其反弹。这个答案的最后一部分的问题是在
atomic::exchange
上旋转,这不是一个好的实现,但是使用
atomic\u flag
编写的东西再好不过了。当然,你需要特定于平台的东西来制作一个真正好的自旋锁。e、 g.x86的
pause
/
\u mm\u pause()
指令,并回退到操作系统辅助的睡眠/唤醒。但我认为一般来说,使用
原子
(如果
总是没有锁的
)的手动旋转旋转锁会比使用
原子标记
@PeterCordes的旋转锁稍微好一些,这正是我的意思。我只是不确定一个或另一个实现在所有情况下都是最好的。例如,使用
exchange
时,您将损失较少的比赛,但缓存命中率更高。所以我相信一切都取决于任务。无论如何,如果OP有这样的问题,如果我是他,我就不会编写自定义自旋锁。@ixSci:Hmm,对于SMT(例如,超线程),在
xchg
上旋转将更多时间阻塞逻辑核心,允许非等待线程运行更多指令。如果我们没有完全可移植代码中的
pause
指令,那么与旋转只读相比,它还可以整体节省功耗。所以,是的,它不像我想象的那样清楚,
.exchange()
对于一个完全通用的实现来说更糟糕。我不鼓励任何人使用通用的便携式C++编写自定义自旋锁;真正的是通过指数回退和类似暂停的东西来仔细调整的。
class my_spinlock {
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:

    void lock()
    {
        while(flag.test_and_set());
    }

    void unlock()
    {
        flag.clear();
    }
};
while (flag.exchange(true));