一般地,对于int num,num++(或++num),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):
由于第5行对应于num++一条指令,我们可以得出结论,在这种情况下num++ 是原子的吗?
如果是这样,是否意味着如此生成num++可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>并强加相关成本,因为它是无论如何原子)?
UPDATE
请注意,这个问题不是增量是否是原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).
如果数据结构中包含多个元素,则它的原子版本不能(始终)无锁.我被告知这对于较大的类型是正确的,因为CPU不能在不使用某种锁的情况下以原子方式更改数据.
例如:
#include <iostream>
#include <atomic>
struct foo {
double a;
double b;
};
std::atomic<foo> var;
int main()
{
std::cout << var.is_lock_free() << std::endl;
std::cout << sizeof(foo) << std::endl;
std::cout << sizeof(var) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出(Linux/gcc)是:
0
16
16
Run Code Online (Sandbox Code Playgroud)
由于原子和foo大小相同,我不认为锁存储在原子中.
我的问题是:
如果一个原子变量使用一个锁,它存储在哪里,这对该变量的多个实例意味着什么?
由于std::atomic::is_lock_free()可能没有真正反映现实[ 参考 ],我正在考虑编写一个真正的运行时测试.然而,当我开始研究它时,我发现这不是一个我认为不可能完成的微不足道的任务.我想知道是否有一些聪明的想法可以做到这一点.
问题:
我正在寻找清除无符号原子的最低非零位的最佳方法,如std::atomic_uint64_t线程安全方式,而不使用额外的互斥锁等.另外,我还需要知道,哪个位被清除了.
示例:
假设,如果存储的当前值是,0b0110我想知道最低的非零位是位1(0索引)并将变量设置为0b0100.
我想出了最好的版本是这样:
#include <atomic>
#include <cstdint>
inline uint64_t with_lowest_non_zero_cleared(std::uint64_t v){
return v-1 & v;
}
inline uint64_t only_keep_lowest_non_zero(std::uint64_t v){
return v & ~with_lowest_non_zero_cleared(v);
}
uint64_t pop_lowest_non_zero(std::atomic_uint64_t& foo)
{
auto expected = foo.load(std::memory_order_relaxed);
while(!foo.compare_exchange_weak(expected,with_lowest_non_zero_cleared(expected), std::memory_order_seq_cst, std::memory_order_relaxed))
{;}
return only_keep_lowest_non_zero(expected);
}
Run Code Online (Sandbox Code Playgroud)
有更好的解决方案吗?
笔记:
C++ 代码应该如何访问与另一个应用程序共享的内存,例如通过memmapd 文件?选项似乎是:
int* p = ...address of shared memory...; *p = 5; *p. 这似乎是不安全的,因为允许编译器假设 的内容p是稳定的,但事实并非如此。volatile.从实验来看,似乎 2 和 3 都在实践中工作(2 没有正确处理弱记忆的复杂性),但是否符合标准?我是否需要使用组合,即访问atomic<volatile int>?
来自C++ Concurrency in Action:
std :: atomic和std :: atomic_flag之间的区别是std :: atomic可能不是无锁的; 实现可能必须在内部获取互斥锁,以确保操作的原子性
我想知道为什么.如果保证atomic_flag是无锁的,为什么它也不能保证atomic<bool>?这是因为会员功能compare_exchange_weak吗?我知道有些机器缺少单一的比较和交换指令,原因是什么?
让我们假设如下:
我在 Linux / Mac OS 上有两个进程。
我有mmap共享内存(或在文件中)。
然后在这两个过程中我都有以下内容:
struct Data{
volatile int reload = 0; // using int because is more standard
// more things in the future...
};
void *mmap_memory = mmap(...);
Data *data = static_cast<Data *>(mmap_memory); // suppose size is sufficient and all OK
Run Code Online (Sandbox Code Playgroud)
然后在我做的其中一个过程中:
//...
data->reload = 1;
//...
Run Code Online (Sandbox Code Playgroud)
在另一个我做的:
while(...){
do_some_work();
//...
if (data->reload == 1)
do_reload();
}
Run Code Online (Sandbox Code Playgroud)
这会是线程/进程间安全的吗?
注意:
这对于 来说并不安全std::atomic<>,因为它不“承诺”有关共享内存的任何内容。此外,从两个不同的过程构建/销毁根本不清楚。
我正在使用 C++ 多处理,使用共享内存将数据从一个传递到另一个。我将一个数组放入共享内存中。进程A将数据复制到数组中,进程B将使用数组中的数据。然而,进程B需要知道数组中有多少项。
目前我正在使用管道/消息队列将数组大小从A传递到B。但我想我可能会在共享内存中放置一个原子变量(如atomic_uint64_t),在进程A中修改它并在进程B中加载它。但是我有以下问题。