[英]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
andthis
will not be invalidated, becauseObject
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.