The theme allocates memory, the main process dies, what happens?
I am currently checking the code I have for memory leaks and this possibility amazed me. Basically, the pseudocode of what I am doing looks like this:
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;
}
This function is inside the DLL. The critical section and other things are initialized by a function that is also inside the same DLL.
Now my main process (which is the GUI) has a Cancel button. When the user clicks on this button, I call the DLL cleanup function that happens to destroy my critical section.
I found that if the user clicks the Cancel button during runtime thread_func()
, the execution thread_func()
will continue. When it reaches the critical section code, the critical section is invalid, so I exit right there. This is how I check for the cancellation event inside the thread (since nothing in my application can cause DLL cleanup at runtime thread_func()
).
I cannot free fileName
in thread_func()
when I found the critical section was invalid. My guess is that I thread_func()
lost access to fileName
since the main process exited. Did I understand correctly? My main question is, if I don't free fileName
in this case, am I at risk of a memory leak?
I've searched for quite a bit of information and haven't found anything so far. I would be very happy if someone could point me in the right direction / answer my question.
Thank!
EDIT:
I decided to do some preliminary tests based on kol's suggestion (see answer below). I noticed something extremely strange that I just can't figure out. Now my code looks like this:
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;
}
And in my GUI, my OnCancel event handler looks something like this:
void OnCancel()
{
threadTerminated = TRUE;
WaitForMultipleObjects(noOfRunningThreads, threadHandles, TRUE, INFINITE);
/* Other cleanup code */
}
I noticed that it was WaitForMultipleObjects()
hanging indefinitely and my GUI was getting unresponsive. Should I WaitForMultipleObjects()
return quickly? Also, no cleanup is done in thread_func()
, if threadTerminated
any TRUE
.
Here's the weirdest part IMO. When I delete WaitForMultipleObjects()
my code works fine! All cleaning takes place, including cleaning the inside thread_func()
. Can someone please help me figure this out?
Please note that I threadTerminated
only check for one point. I'll check it out for other important points later. I am doing this just to see if I understand what is going on.
Thanks again! Your answers are extremely helpful.
source to share
When the process exits, the OS releases all of the allocated memory, so not calling free
on the allocated fileName
will not cause any problems.
Anyway, I would change the code like this:
- Define a flag that indicates whether the stream should end:
bool terminated;
- When the process finishes, set
terminated
totrue
and wait for the stream to end . - In the flow function, check
terminated
at important points (for example, checking the status of each loop). Ifterminated
-true
, stop whatever is done by the thread (such as stop loops), free resources (such as free memory allocated by the thread) and reclaim. - After the thread terminates (that is, after the thread function returns), the process can free every remaining resource (for example, free memory allocated by the process, delete critical sections, etc.) and exit.
This way, you can avoid deleting critical sections before the threads finish, and you can free every allocated resource.
source to share
- Your branch must have some form of looping to make sense.
- When working with threads, you need to invent some way to gracefully terminate them in a safe, predictable way.
- Critical sections are dumb, replace them with a mutex object that the thread can WaitFor.
The correct way to create it would be something like this:
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);
...
}
EDIT:
Please keep in mind that creating and deleting threads creates a lot of overhead and can slow down your program. If they are not worker threads, where the amount of work is significant compared to the overhead, consider keeping the threads alive but dormant for the lifetime of the program.
source to share