我试图用WIN32编写多线程C++应用程序,但由于遇到了困难。其中一个窗口过程创建一个线程,该线程管理此窗口的输出。如果此窗口过程接收到消息(来自其他窗口过程),则应将其发送给他们的线程。一开始我使用_beginthread(.)功能不起作用的东西。然后我用CreateThread(.)试了一下。它起作用了吗?我做错什么了?(我的英语不太好,希望你能理解我的问题)
使用CreateThread(.)的代码:
DWORD thHalloHandle; // global
HWND hwndHallo; // Hwnd of WndProc4
...
LRESULT APIENTRY WndProc4 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static PARAMS params ;
switch (message)
{
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
CreateThread(NULL, 0, thHallo, ¶ms, 0, &thHalloHandle);
return 0 ;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...
}使用_beginthread(.)的代码:
...
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
thHalloHandle = (DWORD)_beginthread (thHallo, 0, ¶ms) ;
return 0;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...thHallo for CreateThread:
DWORD WINAPI thHallo(void *pvoid)
{
static TCHAR *szMessage[] = { TEXT(...), ...};
// Some Declaration
pparams = (PPARAMS) pvoid;
while(!pparams->bKill)
{
MsgReturn = GetMessage(&msg, NULL, 0, 0);
hdc = GetDC(pparams->hwnd);
if(MsgReturn)
{
switch(msg.message)
{
// case....
}
}
}
return 0;
}thHallo _beginthread(.):
void thHallo(void *pvoid)
{
...
// The Same like for CreateThread
...
_endthread();
}发布于 2014-01-03 10:04:42
对CreateThread的调用将线程ID放入thHalloHandle中。对_beginthread的调用将线程句柄放入thHalloHandle。
现在,线程ID与线程句柄不一样。当您调用PostThreadMessage时,您确实需要提供一个线程ID,您只需要为CreateThread变量提供线程ID,我认为这解释了问题的原因。
您的代码缺少错误检查。如果您在调用PostThreadMessage时检查错误,您就会发现PostThreadMessage返回了FALSE。如果您接着调用GetLastError,就会返回ERROR_INVALID_THREAD_ID。我敦促你包括适当的错误检查。
为了解决这个问题,您首先必须更清楚地了解线程ID和线程句柄之间的区别。您应该给thHalloHandle取一个不同的名字:thHalloThreadId。如果您希望使用_beginthread,您必须调用GetThreadId,传递线程句柄,以获得线程ID;或者,使用生成线程ID的_beginthreadex,或者实际上使用CreateThread。
发布于 2014-01-03 10:45:57
事实证明,要从根本上消除_ proving线程/ex()函数是很困难的。这在上个世纪是必要的,VS6是最后一个需要它的Visual版本。这是一个创可贴,允许CRT为内部CRT变量分配线程本地状态.与用于strtok()和gmtime()的函数一样,CRT函数维护内部状态。必须为每个线程分别存储该状态,以便在一个线程中使用strtok()时不会在另一个线程中使用strtok()。它必须存储在线程本地状态。_ state线程/ex()确保重新分配和清理此状态。
在Windows 2000引入线程池时,这一点是必然的.当您的代码被线程池线程调用时,没有可能使内部CRT状态初始化。顺便说一句,他们最难解决的问题是确保线程本地状态在线程停止运行时再次被自动清理。很多程序都死于这一错误,苹果的QuickTime是这些崩溃的一个特别恶劣的来源。
因此,忘记_beginthread()曾经存在过,使用CreateThread()是可以的。
PostThreadMessage()的使用存在严重问题。在_beginthread()代码中使用了错误的参数,这就是为什么它不能工作的原因。但它还有更大的问题。发布的消息只能在消息循环中检索。它可以正常工作,直到不再是您的消息循环发送消息为止。在许多情况下,在GUI应用程序中都会出现这种情况。简单的例子是使用MessageBox()、DialogBox()或用户调整窗口大小。模式代码,由Windows本身提供消息循环。
一个大问题是,代码中的消息循环了解您发布的消息的bean。它们就会掉进桶里,消失得无影无踪。模式循环中的DispatchMessage()调用失败,您发布的消息有一个空窗口句柄。
必须使用PostMessage()来修复这个问题。这需要一个窗口句柄。您可以使用任何窗口句柄,您的主窗口的把手是一个不错的选择。更好的是,您可以使用自己的WndProc()来处理这些线程间消息,从而创建一个专用窗口,该窗口是不可见的。一个非常普遍的选择。DispatchMessage()现在不能再失败了,它也解决了您的错误。
发布于 2014-01-03 10:07:08
您的问题是您需要一个TID (线程标识符)来使用PostThreadMessage。
_beginthread不返回一个TID,而是返回一个线程句柄。
解决方案是使用GetThreadId函数。
HANDLE hThread = (HANDLE)_beginthread (thHallo, 0, ¶ms) ;
thHalloHandle = GetThreadId( hThread );更好的代码(参见文档这里)
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, thHallo, ¶ms, 0, &thHalloHandle ) ;https://stackoverflow.com/questions/20899811
复制相似问题