C++ 如何在c++;不稳定的 `struct MyClass{ ~MyClass(){ //异步调用从my_映射中删除(擦除)条目; //在不同的线程中删除不同的条目。 //需要旋转,因为“this”对象在线程和 //物体的破坏将导致seg故障。 while(my_map.size()>0);//由于编译器的优化,这将永远旋转。 } 无序地图我的地图; };`
在上面的类中,无序映射的元素在析构函数中异步删除,并且当对象在其他线程之间共享时,我必须旋转/休眠。我不能将C++ 如何在c++;不稳定的 `struct MyClass{ ~MyClass(){ //异步调用从my_映射中删除(擦除)条目; //在不同的线程中删除不同的条目。 //需要旋转,因为“this”对象在线程和 //物体的破坏将导致seg故障。 while(my_map.size()>0);//由于编译器的优化,这将永远旋转。 } 无序地图我的地图; };`,c++,multithreading,asynchronous,volatile,unordered-map,C++,Multithreading,Asynchronous,Volatile,Unordered Map,在上面的类中,无序映射的元素在析构函数中异步删除,并且当对象在其他线程之间共享时,我必须旋转/休眠。我不能将my_map声明为volatile,因为它会导致编译错误。我还能在这里做什么?如何告诉编译器my_map.size()将在某个时间点产生0。请不要告诉我这个设计为什么/如何不好;我无法更改设计,因为它是绑定的,因为我无法解释原因,除非我在这里编写数千行代码 编辑:my_map使用spinlock版本进行保护。因此,线程在擦除条目之前会抓取自旋锁。只需while(my_map.size()>
my_map
声明为volatile
,因为它会导致编译错误。我还能在这里做什么?如何告诉编译器my_map.size()
将在某个时间点产生0。请不要告诉我这个设计为什么/如何不好;我无法更改设计,因为它是绑定的,因为我无法解释原因,除非我在这里编写数千行代码
编辑:
my_map
使用spinlock版本进行保护。因此,线程在擦除条目之前会抓取自旋锁。只需while(my_map.size()>0)代码>是我在代码中唯一“天真”的想法。我将它转换为抓取旋转锁,然后检查大小(在一个循环中),它成功了。虽然使用条件变量是正确的方法,但我们使用异步编程模型(如SEDA),它使我们不使用任何休眠/休眠调用。volatile
不是解决此问题的方法volatile
有三种用途:1。访问驱动程序中的内存映射设备,2。信号处理器,3。setjmp用法
反复阅读以下内容,直到理解为止<代码>易失性
在多线程处理中是无用的
像这样天真的旋转锁有三个问题:
编译器被允许缓存结果,因此您可以看到“永远旋转”的行为
在典型情况下,您有竞争条件的风险:线程a
可能会检查锁变量,发现资源是可访问的,但在设置锁变量之前会被抢占。线程B
也找到显示资源可访问的锁变量,因此它将锁定并开始访问资源,然后threadA
唤醒备份,再次锁定变量,并访问资源
存在数据写入顺序问题。如果一个受保护的变量被写入,然后一个锁变量被更改,则不能保证另一个线程不会看到受保护的变量被更改,即使它也可能看到声明已写入的锁变量。编译器和CPU上的无序执行都允许这样做
volatile
只解决了这些问题中的第一个,而没有解决其他两个问题。需要注意的是,默认情况下,x86/x64上的MSVC为volatile
访问添加了内存限制,即使该标准不要求这样做。这恰好解决了第三个问题,但仍然无法解决第二个问题
所有这三个问题的唯一解决方案是使用正确的同步原语:std::atomic
,如果您确实必须旋转锁,最好是std::mutex
,也可能是std::condition\u variable
的锁,该锁将使线程进入睡眠状态,直到发生有趣的事情。考虑使用std::mutex
来保护映射不受并发访问volatile
会导致何种编译器错误?volatile
不起作用你认为这几天它会做什么。大多数编译器都忽略了这个关键字,这并不能使任何东西更线程安全。您寻求的模式是,您需要一个std::condition_变量以及一个锁/互斥锁来保护对my_map
的访问。但奇怪的是,my_map
的拥有类如何在其他线程仍然引用其内部成员的情况下设法被破坏——这听起来像是一个设计问题。您是否考虑过对map实例使用std::shared_ptr?正如上面其他人所建议的,在我的地图访问权限周围需要一个互斥体。请告诉我。我只想添加一个指向的链接。volatile
并不意味着原子!不能将其用于线程同步。使用std::atomic
或锁。volatile
在微基准测试中也很有用,因为它会抑制优化,因此可以用来防止编译器优化掉您想要度量的未使用的代码。但这是一个非常适合的用例。@JesperJuhl这实际上是我使用volatile
的唯一一个用例。
`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;
};`