繁体   English   中英

线程开始执行后,C++ std::thread callable 的 object 指针能否失效?

[英]Can C++ std::thread callable's object pointer be invalidated after the thread begins execution?

我有这段代码...

一个非静态成员方法(作为线程的可调用方法):

void Object::unregister()
{
   ...
}

和这样的析构函数:

Object::~Object()
{
  std::thread cleanup(&Object::unregister, this);
  cleanup.detach();
}

我看到的一个问题是我正在运行一个带有参数this的线程,当析构函数完成时它变得无效,所以我认为这是危险的,因为我没有任何保证,清理线程已经开始 - 这是我的子问题 -如果在unregister的调用完全完成之前this将失效(析构函数完成)是安全的(换句话说,如果它已经开始,但没有完全完成)可以吗?

我会说答案是否定的,因为this指针的副本与 callable 一起使用,但我不确定应用程序的行为,就像它不介意并且一切正常。

如果线程刚刚开始但还没有结束没问题,有没有办法知道线程已经在运行? 调用joinable()是否会在线程已经执行时返回true ,或者它可以在线程执行开始之前返回true

有什么方法可以安全地做到这一点并确保可调用的&Object::unregister并且this不会失效,因为Object同时被破坏了?

如果在取消注册的调用完全完成之前这将失效(析构函数完成)是安全的(换句话说,如果它已经开始,但没有完全完成)可以吗?

不,这不安全。

考虑以下 C 代码:

void Object_unregister(void* obj)
{
    Object* this = (Object*)obj;
    fclose(this->file_handle);
    while (this->ref_counter > 0) {
        fclose(this->ref_array[this->ref_counter]->handle);
        free(this->ref_array[this->ref_counter]);
        this->ref_array[this->ref_counter] = NULL;
        --this->ref_counter;
    }
}

void destroy_Object(Object** this)
{
    pthread_t thread;
    pthread_create(&thread, NULL, &Object_unregister, (void*)*this);
    pthread_detach(&thread);
    free(*this);
    *this = NULL;
}

这就是你的 C++ 代码在做的最基本的事情。 在此代码中,我们创建线程,然后将其分离,然后立即释放 Object 所在的Object空间。 这样,不能保证Object_unregister function 中的this指针将指向传递给它的相同Object

有一个(一般)保证,线程 function 仍将指向与创建线程相同的 function 指针地址,并且它将一直运行到this指针将指向与调用 function 时相同的 memory 地址。

但...

this可能指向0xABADCAFE并且this->file_handle将指向this + sizeof(Object::file_handle) ,但是如果您删除了 object,那么该地址的实际内容可能不再指向Object的有效引用类型。

It could point to some random bit of encryption code, or a new function, or just about anything, but it could still point to the object that was originally there if that memory space was not reallocated by the kernel.

所以不,这不安全。

有什么方法可以安全地做到这一点并确保可调用的&Object::unregister并且this不会失效,因为Object同时被破坏了?

好吧,这取决于您的Object::unregister代码在代码的 rest 上下文中实际执行的操作。 目前还不清楚为什么要线程化析构函数并且不只是调用this->unregister(); 在析构函数中,例如:

Object::~Object()
{
    this->unregister();
}

这与您在代码上下文中获得的一样安全。

但是,如果还有其他事情必须以线程方式完成,您可以做许多架构上的事情来线程化 object 的破坏,从 static 值到锁定机制,但基本上您需要做的是复制您需要unregister的特定值,以便它们在您的线程代码中保持有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM