`struct MyClass {
~MyClass() {
// Asynchronously invoke deletion (erase) of entries from my_map;
// Different entries are deleted in different threads.
// Need to spin as 'this' object is shared among threads and
// destruction of the object will result in seg faults.
while(my_map.size() > 0); // This spins for ever due to complier optimization.
}
unordered_map<key, value> my_map;
};`
我有上面的类,其中无序映射的元素在析构函数中被异步删除,并且必须旋转/睡眠,因为该对象在其他线程之间共享。我无法将my_map
声明为volatile
,因为它会导致编译错误。我还能在这里做什么?我如何告诉编译器在某个时间点my_map.size()
的结果为0。请不要告诉我为什么/这种设计不好。由于无法解释的原因,我无法更改设计,除非我在此处编写了数千行代码。
编辑:my_map
受使用自旋锁版本的保护。因此,线程在擦除条目之前确实会抓住自旋锁。只是while(my_map.size() > 0);
是我在代码中唯一的“天真”旋转。我将其转换为抓取自旋锁,然后(循环查看)大小并正常工作。尽管使用condition_variable
是正确的方法,但我们使用异步编程模型(例如SEDA),该模型将我们绑定为不使用任何睡眠/回避调用。
答案 0 :(得分:4)
volatile
不能解决此问题。 volatile
具有三种用途:1.访问驱动程序中的内存映射设备; 2.信号处理程序; 3. setjmp用法。
一遍又一遍地阅读以下内容,直到它陷入。volatile
在多线程处理中毫无用处。
像这样的天真自旋锁有三个问题:
A
可能会检查lock变量,发现资源可访问,但是在设置lock变量之前先被抢占。随之而来的是线程B
,他也找到了显示资源可访问的锁变量,因此它对其进行锁定并开始访问该资源,然后线程A
唤醒,再次锁定该变量,并且访问资源。 volatile
仅解决了第一个问题,却没有解决其他两个问题。需要注意的是,默认情况下,x86 / x64上的MSVC在volatile
访问中添加了内存隔离,即使标准不要求这样做。碰巧解决了第三个问题,但仍然不能解决第二个问题。
所有这三个问题的唯一解决方案包括使用正确的同步原语:std::atomic<>
,如果您真的必须旋转锁,最好使用std::mutex
,也许还需要std::condition_variable
来锁住,睡觉直到发生有趣的事情的线程。