析构函数和线程安全
Destructor and thread safety
我想创建一个线程安全类,其中包含将元素插入列表的方法。 当其中一个线程销毁实例时,我希望处理列表中的消息,同时防止其他线程插入其他消息。
思路如下:
MyClass{
...
public:
...
void send(string s){
lock_guard<mutex> lock(m);
my_list.push_back(s);
}
~MyClass(){
lock_guard<mutex> lock(m);
for(string s:my_list)
process(s);
}
}
同步是否正确?
对于方法send
我添加了锁,以便多个线程可以以安全的方式调用它。
至于析构函数的问题,线程是否有可能在锁释放和实例的实际销毁之间调用send
? 即for
(以及随后的lock_guard
销毁(是在实际销毁之前执行的最后一个指令,还是在执行析构函数后可能会出现竞争条件?
你可以拆分你的类:
class MyClass
{
public:
void send(const std::string& s){
lock_guard<mutex> lock(m);
my_list.push_back(s);
}
void process_all_messages()
{
lock_guard<mutex> lock(m);
for (const string& s : my_list)
process(s);
//my_list.clear();
}
void process(const std::string& s);
// ... mutex, list, ...
};
并在上面有一个包装纸
class MyClassPerTHread
{
public:
explicit MyClassPerTHread(std::shared_ptr<MyClass> ptr) : ptr(ptr) {}
~MyClassPerTHread(){ ptr->process_all_messages(); }
// MyClassPerTHread(const MyClassPerTHread&);
// MyClassPerTHread(MyClassPerTHread&&);
// MyClassPerTHread& operator=(const MyClassPerTHread&);
// MyClassPerTHread& operator=(MyClassPerTHread&&);
void send(const std::string& s) { ptr->send(s); };
private:
std::shared_ptr<MyClass> ptr;
};
所以在main
,你创建了一个std::shared_ptr<MyClass>
的实例。 您将其传递给每个线程,然后将其包装在MyClassPerTHread
中。
销毁MyClassPerTHread
后,您可以按预期处理消息。
不过,您可能希望调整MyClassPerTHread
以进行移动/复制。
你在这里有一个很好的直觉;析构函数中的lock_guard
根本没有任何好处。
原因如下: 按照这种编写方式,任何对send()
的调用都必须在创建~MyClass()
lock_guard之前完成——否则消息将无法得到处理,send()
很可能在销毁完成后使用 m 和 my_list,从而导致未定义的行为。send()
的调用者无法确保这种情况发生,只能确保在~MyClass()
开始之前完成对send()
的所有调用。
这没关系。大多数类都有(或应该有(客户端序列化销毁的要求。也就是说,客户端必须确保在调用~MyClass()
之前完成send()
的所有调用方。事实上,除非另有说明,否则所有标准库类都有此要求。有些类故意不需要这样做;这很好,但有些异国情调。
幸运的是,这对客户来说并不难做到;他们可以使用shared_ptr或其他东西,正如Jarod42所建议的那样。
tl;博士:
线程是否有可能在锁定释放和实例的实际销毁之间调用 send ?
是的!记录如果他们这样做并摆脱析构函数中的锁,这是客户端错误。
- 从不同线程使用int64的不同字节安全吗
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 在std::thread中,joinable()然后join()线程安全吗
- 在c++队列中使用pop和visit实现线程安全
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 共享队列的线程安全
- boost::文件系统::recursive_directory_iterator多线程安全
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- 线程安全运算符<<
- 如何使缓存线程安全
- C++线程安全:如果只有一个线程可以写入非原子变量,但多个线程从中读取. 会遇到问题吗?
- 提升精神 V2 Qi 语法线程安全吗?
- 线程调用的函数对对象删除是否安全?
- asio 链对象线程安全吗?
- 线程安全队列 c++
- 提供对不同类型的数据(建议、代码审查)的线程安全访问的类
- 有没有更好的方法可以使此代码线程安全?线程局部静态似乎是一个生硬的工具