【发布时间】:2022-08-14 12:41:44
【问题描述】:
我试图一次解决一些复杂的(至少对我而言)异步场景,但我认为理解更简单的情况会更好。
考虑一个已分配内存的对象,由变量携带:
#include <thread>
#include <mutex>
using namespace std;
mutex mu;
class Object
{
public:
char *var;
Object()
{
var = new char[1]; var[0] = 1;
}
~Object()
{
mu.lock();
delete[]var; // destructor should free all dynamic memory on it\'s own, as I remember
mu.unlock();
}
}*object = nullptr;
int main()
{
object = new Object();
return 0;
}
如果同时,detached 中的var 变量,即异步线程,将被使用,在另一个线程中该对象将被删除怎么办?
void do_something()
{
for(;;)
{
mu.lock();
if(object)
if(object->var[0] < 255)
object->var[0]++;
else
object->var[0] = 0;
mu.unlock();
}
}
int main()
{
object = new Object();
thread th(do_something);
th.detach();
Sleep(1000);
delete object;
object = nullptr;
return 0;
}
- 是否有可能
var不会在析构函数中被删除? - 我是否在上面的代码中正确使用
mutex和detached 线程?2.1 我需要
mutex::lock和mutex::unlock以及delete object线路的掩护吗?我也再次单独指出我需要新线程异步.我不需要挂起主线程,而 new 正在运行。我一次需要两个线程。
附言从评论和答案列表中,我终于明白了最重要的事情之一 - 互斥锁。我认为最大的错误是已经锁定的互斥体跳过了锁定和解锁之间的代码。
忘记共享变量,互斥锁本身与它无关。互斥锁只是一种安全暂停线程的机制:
mutex mu; void a() { mu.lock(); Sleep(1000); mu.unlock(); } int main() { thread th(a); th.detach(); mu.lock(); // hangs here, until mu.unlock from a() will be called mu.unlock(); return; }这个概念非常简单——互斥对象(想象)具有标志
isLocked,当(任何)线程调用lock方法并且isLocked为假时,它只是将isLocked设置为真。但是,如果isLocked已经为真,那么低级别的互斥锁会以某种方式挂起调用lock的线程,直到isLocked不会变为假。你可以找到lock方法的部分源代码向下滚动this page。代替互斥锁,可能只使用一个布尔变量,但它会导致undefined behaviour。为什么它被称为共享的东西?因为从多个线程同时使用相同的变量(内存)会产生未定义的行为,所以一个线程到达某个当前可以被另一个线程使用的变量 - 应该等待,直到另一个线程完成使用它,这就是为什么在这里使用互斥锁.
为什么从不同线程访问互斥锁本身不会产生未定义的行为?不知道,去google一下。
-
让你的锁尽可能短,使用 std::scoped lock 来管理你的锁(永远不要像你一样手动解锁)。请参阅:en.cppreference.com/w/cpp/thread/scoped_lock。并且不要分离你的线程。您需要,您需要在删除对象之前加入它(否则您将进行生命周期竞赛)。就我个人而言,我更喜欢 std::async 而不是 std::thread。在删除对象之前与未来同步。 (en.cppreference.com/w/cpp/thread/async)
-
当线程仍在处理对象时,在您的代码中会发生什么被删除。并且您的线程将在进程结束时被终止。换句话说,根本没有生命周期管理。
-
在这个程序中,你稍微混淆了
mu所保护的东西。在Object中,它所保护的只是(一个特定的)对Object::var的访问。但是在do_something中,它用于确保if(object)是检查object是否未被破坏的有效方法。如果执行do_something的线程试图在delete object;和object = nullptr;之间运行会发生什么? -
对不起,我想你没听懂。当
main退出时,你的线程无论如何都会被杀死。通常你想干净地做到这一点。方法是致电join。 -
需要明确的是,人们不只是告诉您将
th.detach();替换为th.join();并没有别的。他们还说将th.join();移动到main的末尾,在main在th工作时需要做的任何其他事情已经完成之后。
标签: c++ mutex stdthread detach stdmutex