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.

+3


source to share


2 answers


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

    to true

    and wait for the stream to end .
  • In the flow function, check terminated

    at important points (for example, checking the status of each loop). If terminated

    - 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.

+4


source


  • 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.

+1


source







All Articles