[英]Passing this pointer to CreateThread in class constructor behaves weird in thread procedure
In the constructor of one of my classes I call the Windows function CreateThread
as last operation. 在我的一个类的构造函数中,我将Windows函数
CreateThread
称为最后一个操作。 The thread is created to execute immediately and I pass the this pointer of my class as lpParameter
. 创建线程立即执行,我将我的类的this指针作为
lpParameter
传递。
In the thread procedure I cast the parameter passed back to a pointer of my class and name it pThis
. 在线程过程中,我将参数传递回我的类的指针并将其命名为
pThis
。
I can see that pThis
points to the same memory location as the this
pointer I passed when I called CreateThread
. 我可以看到
pThis
指向与我在调用CreateThread
时传递的this
指针相同的内存位置 。 However if I look at the member variables accessed by pThis->...
they all have wrong values. 但是,如果我查看
pThis->...
访问的成员变量pThis->...
它们都有错误的值。
I expected the value of this->member_variable
used in the class to which the this pointer belongs to be the same as the one I get when writing pThis->member_variable
in the thread's procedure. 我期望this指针所属的类中使用的
this->member_variable
的值与我在线程过程中编写pThis->member_variable
时得到的值相同。
If I call CreateThread
in another member function ( not the constructor) everything behaves correctly. 如果我在另一个成员函数( 而不是构造函数)中调用
CreateThread
,则一切都正常。
Hence the question: Is it forbidden to call the Windows function CreateThread
from within the constructor of a C++ class? 因此问题是:是否禁止从C ++类的构造函数中调用Windows函数
CreateThread
? If yes, what is the problem? 如果是,问题是什么?
Clarification: 澄清:
1) I can confirm that the object always exists. 1)我可以确认该对象始终存在。 The object gets out of scope only when the entire program ends.
仅当整个程序结束时,对象才会超出范围。 As I already said: calling
CreateThread
from some other member function does work. 正如我已经说过的那样:从其他一些成员函数调用
CreateThread
确实有效。
2) Corrected the 'wired' typo, should have been 'weird', sorry. 2)纠正了'有线'错字,应该是'怪异',对不起。
Some code: 一些代码:
I try to post code snippets reducing things to the bare minimum while maintaining the 'faulty' parts. 我尝试发布代码片段,在保持“错误”部分的同时将事情减少到最低限度。
class CTimerW32 : public CTimer
{
public:
CTimerW32();
~CTimerW32();
private:
static void CALLBACK TimerCallback(LPVOID lpParam, BOOLEAN bReason);
static DWORD WINAPI WaitCompletition(LPVOID lpParam);
private:
HANDLE m_hCompletitionEvent;
HANDLE m_hCompletitionThread;
bool m_bStartDeferred;
};
You can safely ignore the baseclass CTimer
as it is just an abstract baseclass enabling build on different platforms. 您可以安全地忽略基类
CTimer
因为它只是一个抽象基类,可以在不同平台上构建。
CTimerW32::CTimerW32()
{
m_bStartDeferred= false;
m_hCompletitionEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
m_hCompletitionThread= CreateThread(NULL, 0, WaitCompletition, this, 0, NULL);
}
Here I can see that m_hCompletitionEvent
is valid after the call to CreateEvent
. 在这里我可以看到
m_hCompletitionEvent
在调用CreateEvent
之后有效。
DWORD WINAPI CTimerW32::WaitCompletition(LPVOID lpParam)
{
CTimerW32* pThis;
DWORD dwRet;
pThis= (CTimerW32*)(lpParam);
while (true) {
// just wait for the completition event to be signaled
dwRet= WaitForSingleObject(pThis->m_hCompletitionEvent, INFINITE);
// ...
if (pThis->m_bStartDeferred) {
// ...
}
}
Here things are going wrong in the call to WaitForSingleObject
. 这里对
WaitForSingleObject
的调用出错了。 As already stated the this pointer of the object of class CTimerW32
(now pThis
) still has the same value as the this pointer during thread creation. 如前所述,类
CTimerW32
(现在为pThis
)的对象的this指针在创建线程期间仍具有与this指针相同的值。 However the handle in pThis->m_hCompletitionEvent
seems to be random data. 但是,
pThis->m_hCompletitionEvent
的句柄似乎是随机数据。 It is not the value observed after the call to CreateEvent
in the constructor. 它不是在构造函数中调用
CreateEvent
之后观察到的值。
Creating a thread in a constructor should not be an issue. 在构造函数中创建线程应该不是问题。 Also, your object should be fully initialized by the initializer list before any code in the constructor is run to create the thread, so initialization probably isn't an issue.
此外,在运行构造函数中的任何代码以创建线程之前,应由初始化程序列表完全初始化您的对象,因此初始化可能不是问题。
It is likely that the object you're watching is out of scope and its destructor is called prior to you observing it in the new thread. 您正在观察的对象可能超出范围,并且在您在新线程中观察它之前调用其析构函数。 Try creating the object dynamically with new and see if this still happens, I bet it doesn't as the object won't get destroyed when it falls out of scope.
尝试使用new动态创建对象并查看是否仍然发生这种情况,我敢打赌它不会因为当它超出范围时对象不会被销毁。
Obviously, you should keep a pointer to this object in a higher scope so you can eventually delete it too :) 显然,你应该在更高的范围内保留一个指向这个对象的指针,这样你最终也可以删除它:)
You will probably have the best luck debugging this problem with the aid of Application Verifier . 借助Application Verifier,您可能会有最好的运气来调试此问题。 If you turn on the "Basics" option for your program, it will enable PageHeap, which will fault immediately when memory gets freed.
如果打开程序的“基础”选项,它将启用PageHeap,当内存被释放时,它会立即出错。 If you're stack-allocating the timer variable, you're in less luck, but it should be possible to see in the debugger if at the time you notice the corruption, the thread which created the timer is still within the function where the CTimerW32 function was declared.
如果你正在堆栈分配定时器变量,那么你运气不好,但是应该可以在调试器中看到当你注意到损坏时,创建定时器的线程仍然在声明了CTimerW32函数。
Lastly, for this usecase, the Threadpool Timer APIs may work more easily, and with less resource consumption, than creating your own dedicated thread. 最后,对于这个用例, Threadpool Timer API可以比创建自己的专用线程更容易,并且消耗更少的资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.