简体   繁体   English

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

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

I have this chunk of code...我有这段代码...

A non-static member method (serving as callable for thread):一个非静态成员方法(作为线程的可调用方法):

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

and destructor like this:和这样的析构函数:

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

What I see as a problem is that I am running a thread with parameter this which become invalidated when destructor finishes, so I assume it is dangerous, because I do not have any garantee, that the cleanup thread already started - and this my subquestion - is safe if this would be invalidated (destructor finishes) before the call to unregister finishes completely (in other words is it ok, if it already started, but did not finish completely) ?我看到的一个问题是我正在运行一个带有参数this的线程,当析构函数完成时它变得无效,所以我认为这是危险的,因为我没有任何保证,清理线程已经开始 - 这是我的子问题 -如果在unregister的调用完全完成之前this将失效(析构函数完成)是安全的(换句话说,如果它已经开始,但没有完全完成)可以吗?

I would say that answer is No as the copy of this pointer is used with callable, but I am not sure as the app behaves, like it does not mind and everything is OK.我会说答案是否定的,因为this指针的副本与 callable 一起使用,但我不确定应用程序的行为,就像它不介意并且一切正常。

If it is ok that thread just started and did not finish yet, is there any way to know that the thread is already running?如果线程刚刚开始但还没有结束没问题,有没有办法知道线程已经在运行? Would usage of call to joinable() return me true just when the thread is already executing or it can return true before the thread's execution started?调用joinable()是否会在线程已经执行时返回true ,或者它可以在线程执行开始之前返回true

Is there any way how to do it safe and be sure that callable &Object::unregister and this will not be invalidated, because Object was destroyed meanwhile?有什么方法可以安全地做到这一点并确保可调用的&Object::unregister并且this不会失效,因为Object同时被破坏了?

is safe if this would be invalidated (destructor finishes) before the call to unregister finishes completely (in other words is it ok, if it already started, but did not finish completely)?如果在取消注册的调用完全完成之前这将失效(析构函数完成)是安全的(换句话说,如果它已经开始,但没有完全完成)可以吗?

No, it's not safe.不,这不安全。

Consider the following C code:考虑以下 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;
}

This is, at a very basic level, what your C++ code is doing.这就是你的 C++ 代码在做的最基本的事情。 In this code, we create the thread, then detach it, then immediately free the memory space where the Object was at.在此代码中,我们创建线程,然后将其分离,然后立即释放 Object 所在的Object空间。 In this way, there's no guarantee that the this pointer in the Object_unregister function will point to the same Object that was passed to it.这样,不能保证Object_unregister function 中的this指针将指向传递给它的相同Object

There is a (general) guarantee that the thread function will still point to the same function pointer address the thread was created with, and that it will run until that function has completed, and in the above code, there is a guarantee that the this pointer will point to the same memory address from when the function was called.有一个(一般)保证,线程 function 仍将指向与创建线程相同的 function 指针地址,并且它将一直运行到this指针将指向与调用 function 时相同的 memory 地址。

But...但...

this could point to 0xABADCAFE and this->file_handle will point to this + sizeof(Object::file_handle) , but if you've deleted the object, then what is actually at that address could no longer point to a valid reference of an Object type. 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. 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.

So no, it's not safe.所以不,这不安全。

Is there any way how to do it safe and be sure that callable &Object::unregister and this will not be invalidated, because Object was destroyed meanwhile?有什么方法可以安全地做到这一点并确保可调用的&Object::unregister并且this不会失效,因为Object同时被破坏了?

Well it depends on what your Object::unregister code actually does in the context of the rest of your code.好吧,这取决于您的Object::unregister代码在代码的 rest 上下文中实际执行的操作。 It's not immediately clear why you want to thread the destructor and you don't just call this->unregister();目前还不清楚为什么要线程化析构函数并且不只是调用this->unregister(); in the destructor, example:在析构函数中,例如:

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

That's as safe as you can get in the context of your code.这与您在代码上下文中获得的一样安全。

But if there's other things that necessarily need to be done in a threaded way, you could do many architectural things to thread the destruction of the object, from static values to locking mechanisms, but essentially what you would need to do is make copies of the specific values you need to unregister so they remain valid in your thread code.但是,如果还有其他事情必须以线程方式完成,您可以做许多架构上的事情来线程化 object 的破坏,从 static 值到锁定机制,但基本上您需要做的是复制您需要unregister的特定值,以便它们在您的线程代码中保持有效。

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

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