2013-02-13 111 views
3

我目前正在检查一些代码,我有内存泄漏,这种可能性让我感到震惊。基本上,我在做什么的伪代码如下所示,线程分配内存,主进程死亡,会发生什么?

void thread_func() 
{ 
    char *fileName = malloc(someSize); 
    /* Do something with fileName and other things */ 
    /* Enter a critical section */ 
    modify some global variables 
    /*Exit critical section */ 
    free(fileName); 
    return; 
} 

此函数驻留在DLL中。关键部分和其他东西由同样驻留在同一个DLL中的函数初始化。

现在,我的主进程(这是一个GUI)有一个取消按钮。当用户点击该按钮时,我会调用DLL的清理函数,这个函数恰好会破坏我的关键部分。

我发现如果用户在执行thread_func()期间点击取消,thread_func()将继续执行。当它到达关键部分代码时,关键部分是无效的,所以我在那里退出。这是我如何检查线程内的取消事件(因为在执行thread_func()期间,我的应用程序中没有其他任何东西可以调用DLL的清除)。

我不能免费fileNamethread_func()当我发现临界区无效。我的猜测是因为thread_func()由于主进程退出而失去对fileName的访问。我的猜测是对的吗?我的主要问题是,如果我在这种情况下没有免费使用fileName,我是否会冒内存泄漏的风险?

我已经搜索了很多相关信息,到目前为止还没有找到任何东西。如果有人能指出我正确的方向/回答我的问题,我会非常高兴。

谢谢!

编辑:

,我决定做根据科尔的建议的一些初步测试(见下面的回答)。我注意到了一些我无法理解的奇怪东西。现在,我的代码如下:

void thread_func() 
{ 
    char *fileName = malloc(someSize); 
    /* Do something with fileName and other things */ 

    if(threadTerminated) 
    { 
     /* Cleanup */ 
     return; 
    } 

    /* Enter a critical section */ 
    modify some global variables 
    /*Exit critical section */ 
    free(fileName); 
    return; 
} 

而在我的GUI,我OnCancel事件处理程序是这样的:

void OnCancel() 
{ 
    threadTerminated = TRUE; 
    WaitForMultipleObjects(noOfRunningThreads, threadHandles, TRUE, INFINITE); 

    /* Other cleanup code */ 
} 

我注意到,WaitForMultipleObjects()无限期挂起我的图形用户界面变得无法响应。 WaitForMultipleObjects()不应该快速返回?另外,如果threadTerminatedTRUE,则在thread_func()中没有发生清理。

这是IMO最奇怪的部分。当我删除WaitForMultipleObjects()时,我的代码工作得很好!所有的清理工作都会发生,包括thread_func()内的清理。有人能帮我理解吗?

请注意,我现在只在一个点上检查threadTerminated。稍后我会在其他重要的部分检查它。我只是为了看看我是否了解发生了什么。

再次感谢!你的回答非常有帮助。

+0

有不同类型的内存泄漏,在不增加它往往是更不方便的不是一个实际的问题,因为程序终止反正和泄漏是不随时间增长泄漏的情况。 – 2013-02-13 15:12:14

+0

@claptrap,好点!但是我想清除任何我发现的内存泄漏情况。 – 2013-02-13 16:06:37

+0

如果仅在进程退出时调用DLL的清理函数,则不要打扰销毁关键部分。该建筑正在拆除,所以你不需要扫地。如果您需要处理DLL被卸载但进程将继续进行的情况,那么您需要根据现有答案将清理与线程同步。请记住,即使在没有关键部分的情况下,当线程仍在运行代码时,也无法安全地卸载DLL。 – 2013-02-13 22:07:15

回答

4

当进程终止时,操作系统将释放所有已分配的内存,因此不会在分配的fileName上调用free不会导致任何问题。

无论如何,我会改变代码的方式如下:

  1. 定义指示线程是否应该终止的标志:bool terminated;
  2. 当进程即将结束,设置terminatedtrue,和wait for the thread to terminate
  3. 在线程函数中,请检查terminated的重要位置(例如,在每个循环的条件检查中)。如果terminatedtrue,则停止线程完成的所有操作(例如,停止循环),释放资源(例如线程分配的空闲内存)并返回。
  4. 线程终止后(即线程函数返回后),进程可以释放每个剩余的资源(例如,进程分配的空闲内存,删除关键部分等)并退出。

这样可以避免在线程终止前删除关键部分,并且您可以释放每个分配的资源。

+1

我不会推荐一个布尔。改为使用事件,以便线程可以休眠而不会产生无意义的CPU负载。看到我的答案。 – Lundin 2013-02-13 15:22:45

+0

@Lundin我不确定一个事件对于这个目的更好。我的意思是没有必要在这面旗帜上等待。线程完成它的工作,并且在决策点,它检查标志以决定它是否可以继续执行或者应该以优雅的方式终止。 (Delphi的设计者使用相同的逻辑:TThread类具有终止属性,这是一个布尔值。) – kol 2013-02-13 15:49:59

+0

感谢您的回答!这绝对是对我的问题可能的解决方案。 @伦丁,你为什么不推荐一个布尔?只是好奇。 – 2013-02-13 15:51:35

1
  • 你的线程可能应该有某种形式的循环才有意义。
  • 使用线程时,您需要发明一些方法以安全,可预测的方式正常终止它们。
  • 关键部分是钝的,用线程可以等待的互斥对象替换它们。

设计,这将是这样的正确的方法:

HANDLE h_event_killthread = CreateEvent(...); 
HANDLE h_mutex = CreateMutex(...); 

... 

void thread_func() 
{ 
    const HANDLE h_array [] = 
    { 
    h_event_killthread, 
    h_mutex 
    }; 

    ... // malloc etc 

    bool time_to_die = false; 

    while(!time_to_die) 
    { 
    DWORD wait_result; 
    wait_result = WaitForMultipleObjects(2,   // wait for 2 handles 
             h_array, // in this array 
             FALSE,  // wait for any handle 
             INFINITE); // wait forever 

    if(wait_result == WAIT_OBJECT_0) // h_event_killthread 
    { 
     time_to_die = true; 
    } 
    else if(wait_result == (WAIT_OBJECT_0+1)) //h_mutex 
    { 
     // we have the mutex 
     // modify globals here 
     ReleaseMutex(h_mutex); 

     // do any other work that needs to be done, if meaningful 
    } 
    } 

    cleanup(); 
} 


// and then in the GUI: 

void cancel_button() 
{ 
    ... 
    SetEvent(h_event_killthread); 
    WaitForSingleObject(the_thread, INFINITE); 
    ... 
} 

编辑:

请有记住,创建和删除线程创造了很多的开销代码和可能减慢程序。除非它们是工作线程,工作量相对于开销而言是重要的,否则应考虑在线程整个生命周期中保持线程活着但睡着。

+1

我强烈建议[此](http://www.flounder。com/badprogram.htm)优秀的阅读。 – Lundin 2013-02-13 15:30:44

+0

感谢您的回答!这绝对看起来像我所拥有的更好的设计。什么是WAIT_OBJECT_0?另一个问题,你为什么说关键部分是钝的?此外,该链接看起来很有趣。非常感谢你! – 2013-02-13 15:55:16

+0

哦,不用关心'WAIT_OBJECT_0',用google搜索了一下。另一件事,目前我的应用程序中只有一小部分是多线程的,它要求所有线程同时启动(不是我的决定),否则我可能会考虑暂停线程的建议。 – 2013-02-13 16:05:05