我已经阅读了很多文章和问题,例如this,this和this,所提供的所有答案都没有确定在这种情况下应该做些什么:
目前我正在编写一个并发程序,我需要同时访问std::priority_queue<std::pair<int, int>>
的大小和顶部多次,同时在其他地方推送和弹出元素。
但是每次需要读取时锁定mutex
效率太低(而且读者和编写者问题的解决方案也不够有效)。
唯一足够好的是将这三个属性包装在std::atomic
中并在队列的每次更新时更新原子,如果只有编译器允许我这样做的话,这将起作用。
可悲的是,g ++ 7.2.0输出了
“对'__atomic_load'的未定义引用”
链接时出错信息。
我尝试将-latomic
添加到CMakeLists.txt
,但我得到了
“/ usr / bin / ld:找不到-latomic”
而是错误(我不允许更改或更新编译器)。
我的结构是POD类型(我用static_assert
检查过),所以我不明白为什么它不起作用。我怎样才能让它发挥作用?
编辑:我编译了与第三个链接中的代码几乎相同的代码,
#include <iostream>
#include <atomic>
using namespace std;
struct Vec {
int x, y, z;
};
int main() {
std::atomic<Vec> x;
Vec a;
x = a;
}
并收到以下错误消息
CMakeFiles/folder.dir/vec.cpp.o: In function `std::atomic<Vec>::store(Vec, std::memory_order)':
vec.cpp:(.text._ZNSt6atomicI3VecE5storeES0_St12memory_order[_ZNSt6atomicI3VecE5storeES0_St12memory_order]+0x47): undefined reference to `__atomic_store'
collect2:错误:ld返回1退出状态
从评论中移动/说明:
g ++ std::atomic<T>
实现requires libatomic for non-natively supported types。
我可以用-latomic
重现并修复你的错误:
[matteo@teolapkubuntu /tmp]$ g++ -O3 test.cpp
/tmp/cc7YRyMy.o: In function `main':
test.cpp:(.text.startup+0x3f): undefined reference to `__atomic_store'
collect2: error: ld returned 1 exit status
[matteo@teolapkubuntu /tmp]$ g++ -O3 test.cpp -latomic
[matteo@teolapkubuntu /tmp]$
尽管如此,如果你的工具链不提供libatomic,我也不会太担心。
libatomic中非本机支持类型的原子存储库可以归结为either a compare-exchange loop(参见LARGER
macro),或者,在“退化”情况下(T
大于16字节),to a plain mutex(libat_lock_n
使用目标地址的散列并锁定相应的从一些全局锁定锁定)。
这是你可以自己实现的所有东西,没有太多麻烦 - 实际上,你比libatomic的编写者处于更好的位置,因为你可以添加额外的数据成员,而不必从锁池中利用目标数据本身或其地址。
首先,我尝试使用普通的互斥锁保护您单独的数据副本。鉴于这种互斥量应该在极短的时间内使用,我不会期望有太多争用;鉴于你有一个作家和多个读者,如果你的编译器足够新,你可以尝试使用std::shared_mutex。
如果普通的互斥体太慢,你可以fall back to a spinlock;再次,因为它应该在极短的时间内服用,对你的用例来说应该是完全没问题的。如果你需要更高的速度,你将不得不弄脏with extra tricks(可能使用优化的RW自旋锁)。