使用操作当前对象的线程是否安全
Is it safe to use thread that manipulate the current object?
>想象一下我有以下内容:
struct A {
std::vector<int> _vect;
std::mutex _mutex;
void f () {
std::thread t1(&A::work, this);
std::thread t2(&A::work, this);
t1.join();
t2.join();
}
void work () {
std::vector<int> cvect;
while (true) {
bool keep = false;
_mutex.lock();
// get_next() modify the internal state of this
keep = get_next();
cvect = _vect; // copy of _vect
_mutex.unlock();
if (!keep) break;
// Do some stuff that does not require the `this`, e.g.:
std::sort(cvect.begin(), cvect.end());
int v = cvect.back() - cvect.front();
}
}
bool get_next () {
// This methods modify _vect
_vect = std::vector<int>{1, 2, 3, 4}; // e.g.
}
}
int main () {
A a;
a.f();
return 0;
}
上面的编译和工作(使用更复杂的实现)。
它是否安全(如果不是,我怎样才能使其安全?
在
_work
期间可能会发生什么错误(哪些案件没有得到正确处理?
当前的实现有一个微妙的错误。我想知道您是否在实际代码中也有它。
while (true) {
_mutex.lock();
// get_next() modify the internal state of this
if (!get_next()) break;
_mutex.unlock();
在这里,中断将退出循环并保持互斥锁锁定状态。欢迎来到死锁!为了解决这个微妙的问题,我真的建议避免使用 mutex.lock()
/unlock()
.相反,应该使用std::lock_guard
或std::unique_lock
。
规则如下:
- 从不同的线程读取和写入同一变量是未定义的行为。
- 在没有任何锁定或原子操作的情况下同时读取和写入同一变量可能会导致内存不可见。 一个线程可能不会"读取"另一个线程写入的最新值
- 从两个不同的线程读取相同的变量是线程安全的。
对于您的问题:
做一些需要
this
指针的事情。
如果"东西"只是从this
指出的成员那里读取,那么整个锁定是多余的。
另一方面,如果一个线程以某种方式更改this
,则锁定是强制性的。在这种情况下,锁使并发操作是线程安全的
做一些不需要
this
指针的事情。
同样,如果在两个线程中执行的唯一操作是读取,则该方法是线程安全的。 如果一个线程正在写入变量(无论它是否是成员变量!线程只能看到内存地址),而另一个线程正在读取/写入它,则必须锁定该变量或为其使用原子。
_work期间可能发生什么错误(哪些情况不正确) 处理?
在行为未定义的土地上,任何事情都可能发生。 例如,当您取消引用无效内存地址时会发生什么?
PS. 使用标准 RAII 包装器锁定互斥锁,不要自己手动锁定。
相关文章:
- 如何检查线程是否锁定
- 并发/多线程:是否可以以这种方式生成相同的输出?
- 当我在C++中调用 struce 的只读静态成员时,线程是否安全
- 检查分离的线程是否还活着?
- 将正常函数的工作分配给多个线程是否安全
- 最大线程数 - 如何确定C++线程是否并行运行?
- 如何确定其他线程是否正在运行?
- 线程是否真的在调用 std::future::get() 后启动
- 如何知道分离的STD ::线程是否完成了执行
- 通知线程是否始终需要在修改期间锁定共享数据
- 只写到共享 std::unordered_map 线程是否安全
- 检查线程是否在 c++11 中完成
- C++ 互斥 - 检查另一个线程是否正在等待
- 提升::作用域的线程是否自动分离
- 以下单例实现线程是否安全?
- 确定线程是否已退出
- 我的不同线程是否会看到更新后的shared_ptr对象
- 使用操作当前对象的线程是否安全
- 此同步对象实现线程是否安全
- 线程是否共享一些类字段