头文件中的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的简单动作将导致未定义的行为。

更糟糕的是,lpParamats的地址。如果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 ++内存模型做出了根本错误的假设,因此我会假设其他事情(您未显示)在您的代码中是错误的。但这应该可以帮助您入门。

10-08 11:27