views:

87

answers:

2

Greetings, everyone!

I have a class (say, "Switcher" ) that executes some very-very long operation and notifies its listener, that operation is complete. The operation is long, and I isolate actual switching into separate thread:

class Switcher
{
public:
    // this is what other users call:
    void StartSwitching()
    {
        // another switch is initiated, I must terminate previous switching operation:
        if ( m_Thread != NULL )
        {
            if ( WaitForThread(m_Thread, 3000) != OK ) 
            {
                TerminateThread(m_Thread);
            }
        }
        // start new switching thread:
        m_Thread = StartNewThread( ThreadProc );
    }

    // this is a thread procedure:
    static void ThreadProc()
    {
        DoActualSwitching();
        NotifyListener();
    }

private:
    Thread m_Thread;
};

The logic is rather simple - if user initiates new switching before the previous one is complete, I terminate previous switching (don't care of what happens inside "DoActualSwitching()") and start the new one. The problem is that sometimes, when terminating thread, I loose the "NotifyListener()" call.

I would like to introduce some improvements to ensure, that NotifyListener() is called every time, even if thread is terminated. Is there any pattern to do this? I can only think of another thread, that infinitely waits for the switcher and if the switcher is done (correctly or by termination), it can emit notification. But introducing another thread seems an overplay for me. Can you think of any other solution (p.s. the platform is win32)?

Thank you!

+2  A: 

First, you should never call TerminateThread. You cannot know which operation is terminated when calling TerminateThread and so that could lead to memory leaks/resource leaks/state corruption.

To get your thread to be interruptable/cancelable, you supply a 'cancel' state, which is checked by the thread itself. Then your notify end will always work.

Christopher
+1  A: 

TerminateThread() here whacks the thread, and if it was inside DoActualSwitching(), that's where it'll die, and NotifyListener() will not be called on that thread. This is what TerminateThread() does, and there is no way to make it behave differently.

What you are looking for is a bit more graceful way to terminate the thread. Without more info about your application it's difficult to suggest an optimal approach, but if you can edit DoActualSwitching(), then I'd add

if (WAIT_OBJECT_0 == WaitForSingleObject(m_ExitThreadEvent, 0))
    break;

into the loop there, and call SetEvent(m_ExitThreadEvent) instead of TerminateThread(). Of course you'll need to create the event and add the handle to the class. If your model suggest that there is only one switching thread at a time, I'd use autoreset event here, otherwise some more code is needed.

Good luck!

Rom
Thanks! Unfortunately, DoActualSwitching() is a large thread-blocking function, called from external SDK and we have no chance to modify it. Otherwise, m_ExitThreadEvent would be a great solution =)
SadSido