头文件中的typedef
:
typedef struct tagMYSTRUCT {
wchar_t mystr[40] = { 0 };
DWORD threadId = NULL;
HANDLE threadHandle = NULL;
HWND receiverWnd = NULL;
} MYSTRUCT, *PMYSTRUCT;
线程创建:
MYSTRUCT ats = *(PMYSTRUCT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYSTRUCT));
wcscpy(ats.mystr, L"hello");
ats.threadHandle = CreateThread(NULL, 0, MyThread, &ats, 0, &(ats.threadId));
这是使用HeapFree()函数的线程。但是它崩溃了。我认为这是不好的做法,但我想知道为什么。背后的逻辑是什么,为什么HeapFree会使程序崩溃?
DWORD WINAPI MyThread(LPVOID lpParam) {
MYSTRUCT ActiveStruct = *(PMYSTRUCT)lpParam;
if (lpParam != NULL) {
std::cout << "1" << std::endl; // Gets printed.
HeapFree(GetProcessHeap(), NULL, lpParam);
std::cout << "2" << std::endl; // Crashes before this line.
}
...
}
最佳答案
显然,您来自另一种语言,该语言与C ++不同,将指针和引用的概念融合在一起。您的用法在C ++中非常不合适。通过使用非标准函数(HeapAlloc()
是Windows特定的,不是C ++等)来管理内存,会使事情变得更加复杂。
如果要使用HeapAlloc()
(非标准C ++,特定于Windows)或任何动态分配内存的标准函数,则需要将结果存储在指针中。
MYSTRUCT ats = *(PMYSTRUCT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYSTRUCT));
wcscpy(ats.mystr, L"hello");
ats.threadHandle = CreateThread(NULL, 0, MyThread, &ats, 0, &(ats.threadId));
它的作用是将
HeapAlloc()
返回的指针转换为指向MYSTRUCT
的指针,取消引用将该内存位置解释为MYSTRUCT
值的指针,然后将该值复制到ats
中。至少这是内存泄漏-由
HeapAlloc()
分配的内存丢失(不再使用,其地址未存储在任何地方),并且您将ats
的地址传递给线程函数。因此,由
HeapAlloc()
分配的内存与传递给线程函数的地址之间没有任何关系。更糟糕的是线程函数本身,我在这里对此进行了简化
DWORD WINAPI MyThread(LPVOID lpParam)
{
MYSTRUCT ActiveStruct = *(PMYSTRUCT)lpParam;
if (lpParam != NULL)
{
std::cout << "1" << std::endl; // Gets printed.
HeapFree(GetProcessHeap(), NULL, lpParam);
std::cout << "2" << std::endl; // Crashes before this line.
}
}
lpParam
将包含创建线程的函数所传递的函数中ats
的地址。如果创建线程的函数已返回(毕竟,线程并行运行),则该
ats
将不再存在。如果发生这种情况,lpParam
将是一个悬空指针(就程序而言,该对象的地址不再存在)。ActiveStruct
现在将成为一个本地对象,该本地对象在传递给函数的地址处包含该对象的副本。换句话说,它是func先前分配的ats
的本地副本。如果该ats
不再存在,并且传递的地址是悬空的,则创建ActiveStruct
的简单动作将导致未定义的行为。更糟糕的是,
lpParam
是ats
的地址。如果ats
仍然存在(即未返回创建线程的函数),则不是在堆上创建的,因此不应使用HeapFree()
释放它。如果它不再存在,则也不应将其传递给HeapFree()
。无论哪种方式,都要求HeapFree()
释放未使用HeapAlloc()
分配的内存。实际上可以保证会导致运行时错误。至少,您需要将创建线程的代码更改为
MYSTRUCT *ats = (PMYSTRUCT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYSTRUCT)); // note changed position of *
wcscpy(ats->mystr, L"hello"); // note usage of ats as a pointer
DWORD threadID; // we need these since ats is being released by the thread function
HANDLE threadHandle; // it is not a good idea for CreateThread() to use them
threadHandle = CreateThread(NULL, 0, MyThread, ats, 0, &(threadId)); // changes since ats is now a pointer
和线程功能
DWORD WINAPI MyThread(LPVOID lpParam)
{
MYSTRUCT *ActiveStruct = (PMYSTRUCT)lpParam; // this is now a pointer
if (lpParam != NULL)
{
std::cout << "1" << std::endl; // Gets printed.
HeapFree(GetProcessHeap(), NULL, lpParam);
std::cout << "2" << std::endl; // Crashes before this line.
}
}
由于您对C ++内存模型做出了根本错误的假设,因此我会假设其他事情(您未显示)在您的代码中是错误的。但这应该可以帮助您入门。