有没有一种方法可以让我们编写一些代码来为compare_exchange的“弱”版本产生“虚假失败”?虽然相同的代码应该可以很好地用于compare_exchange_strong?
我希望了解 2 个 api 的“弱”版本和“强”版本之间的真正区别,有任何示例吗?
多谢!
我正在阅读《C++ Concurrency in Action》第二版。下面的代码来自清单 7.6。它pop()使用危险指针来实现堆栈。
std::shared_ptr<T> pop() {
std::atomic<void*>& hp = get_hazard_pointer_for_current_thread();
node* old_head = head.load(); // #1
do {
node* temp;
do {
temp = old_head;
hp.store(old_head); // #2
old_head = head.load(); // #3
} while (old_head != temp); // #4
} while (old_head &&
!head.compare_exchange_strong(old_head, old_head->next));
hp.store(nullptr);
// ...
}
Run Code Online (Sandbox Code Playgroud)
书中解释了内循环的作用:
您必须在
while循环中执行此操作,以确保node在读取旧head指针#1和设置危险指针#2之间没有删除。在此窗口期间,没有其他线程知道您正在访问该特定节点。幸运的是,如果旧head节点要被删除,head那么它本身一定已经发生了变化,因此您可以检查这一点并继续循环,直到您知道该head指针仍然具有与您设置危险指针相同的值#4。
根据 的实现,如果另一个线程在和之间pop删除了头节点,则将被修改为新节点。pop …
我想知道是否可以编写std::atomic<>供 AVR \xc2\xb5C 使用的内容。__atomic_xxx()不幸的是,avr-gcc 中没有实现内置函数。
据我了解,uint8_tAVR 上的基本加载/存储是原子的,但例如operator++()不是因为它意味着 rmw 循环。因此,对于这些操作,必须禁用中断,因为这是该硬件上唯一的并发形式。对于更大的类型,uint8_t甚至operator=(T)需要防止中断。
另一方面,必须对模板的数据成员应用内存屏障:例如,该数据成员具有必须使用的std::atomic<>名称来完成机器上的实际加载/存储。valueasm volatile("" : "+m" (value));
这足以实施吗std::atomic<>?
由于此实现是无锁的,因此它应该可用于该硬件上的 ISR。
\n如果要实现这一点,std::atomic<>这将导致ISR内的机器代码效率低下,因为不必要的中断禁用和/或内存屏障会阻止优化。
std::atomic<>好吧,这可以通过扩展不安全操作的接口来规避。
另一方面:std::atomic_ref<>在 ISR 之外实施和使用它是否更可行?
对原子对象M执行释放操作A后,M的修改顺序的最长连续子序列包括:
- 由执行 A 的同一线程执行写入。(C++20 之前)
- 任何线程对 M 进行原子读-修改-写操作。被称为以 A 为首的释放序列。
Q1:为什么需要释放顺序的概念?
A1:参见“释放顺序”是什么意思?
Q2:C++20中第一项被删除了吗?
问题 3:为什么读-修改-写操作符合发布顺序,而纯写操作则不然?
宽松的 RMW 有什么特别之处,可以让它们形成一个链,而不需要成为获取加载和释放存储?是用计算机体系结构术语,还是用 C++ 语言形式主义?或者换句话说,硬件如何支持原子 RMW 的释放序列语义,但具有中断连接的纯存储?
与我之前的问题类似,请考虑以下代码
-- 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 in Action:
std :: atomic和std :: atomic_flag之间的区别是std :: atomic可能不是无锁的; 实现可能必须在内部获取互斥锁,以确保操作的原子性
我想知道为什么.如果保证atomic_flag是无锁的,为什么它也不能保证atomic<bool>?这是因为会员功能compare_exchange_weak吗?我知道有些机器缺少单一的比较和交换指令,原因是什么?
在上面的问题中,显然我们可以std::mutex用来保持线程安全.我想知道何时使用哪一个.
classs A
{
std::atomic<int> x;
public:
A()
{
x=0;
}
void Add()
{
x++;
}
void Sub()
{
x--;
}
};
Run Code Online (Sandbox Code Playgroud)
和
std::mutex mtx;
classs A
{
int x;
public:
A()
{
x=0;
}
void Add()
{
std::lock_guard<std::mutex> guard(mtx);
x++;
}
void Sub()
{
std::lock_guard<std::mutex> guard(mtx);
x--;
}
};
Run Code Online (Sandbox Code Playgroud) 在C++内存模型中,所有顺序一致操作的所有加载和存储都有一个总顺序.我想知道这是如何与具有其他内存排序的操作交互,这些内存排序在顺序一致的加载之前/之后排序.
例如,考虑两个线程:
std::atomic<int> a(0);
std::atomic<int> b(0);
std::atomic<int> c(0);
//////////////
// Thread T1
//////////////
// Signal that we've started running.
a.store(1, std::memory_order_relaxed);
// If T2's store to b occurs before our load below in the total
// order on sequentially consistent operations, set flag c.
if (b.load(std::memory_order_seq_cst) == 1) {
c.store(1, std::memory_order_relaxed)
}
//////////////
// Thread T2
//////////////
// Blindly write to b.
b.store(1, std::memory_order_seq_cst)
// Has T1 set c? If so, then we know our store to b occurred before …Run Code Online (Sandbox Code Playgroud) 在我的MAC OS上,atomic<T*>是免费的.
#include <iostream>
#include <atomic>
int main() {
std::cout << std::atomic<void*>().is_lock_free() << std::endl;
return 0;
}
output: 1
Run Code Online (Sandbox Code Playgroud)
我想知道是否atomic<T*>总是免费锁定?
有参考介绍吗?
由于今天是美国的感恩节,所以我将被指定为土耳其来问这个问题:
Take something as innocuous as this. An atomic with a simple plain old data type such as an int:
atomic<int> x;
cout << x;
Run Code Online (Sandbox Code Playgroud)
The above will print out garbage (undefined) data. Which makes sense given what I read for the atomic constuctor:
(1) default constructor
Leaves the atomic object in an uninitialized state. An uninitialized atomic object may later be initialized by calling atomic_init.
Feels like an odd committee decision. But I'm sure they had their reasons. …