set a global flag on shut down instead calling Delete() on all threads sequentially which could take an eternity if there were many of them

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54021 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-06-07 16:54:29 +00:00
parent 3a105cbc3c
commit abbcf16d06

View File

@@ -53,20 +53,18 @@ public:
virtual bool OnInit(); virtual bool OnInit();
public: // critical section protects access to all of the fields below
wxCriticalSection m_critsect;
// all the threads currently alive - as soon as the thread terminates, it's // all the threads currently alive - as soon as the thread terminates, it's
// removed from the array // removed from the array
wxArrayThread m_threads; wxArrayThread m_threads;
// crit section protects access to all of the arrays below
wxCriticalSection m_critsect;
// semaphore used to wait for the threads to exit, see MyFrame::OnQuit() // semaphore used to wait for the threads to exit, see MyFrame::OnQuit()
wxSemaphore m_semAllDone; wxSemaphore m_semAllDone;
// the last exiting thread should post to m_semAllDone if this is true // indicates that we're shutting down and all threads should exit
// (protected by the same m_critsect) bool m_shuttingDown;
bool m_waitingUntilAllDone;
}; };
// Create a new application object // Create a new application object
@@ -182,16 +180,16 @@ class MyThread : public wxThread
{ {
public: public:
MyThread(MyFrame *frame); MyThread(MyFrame *frame);
virtual ~MyThread();
// thread execution starts here // thread execution starts here
virtual void *Entry(); virtual void *Entry();
// called when the thread exits - whether it terminates normally or is // write something to the text control in the main frame
// stopped with Delete() (but not when it is Kill()ed!) void WriteText(const wxString& text)
virtual void OnExit(); {
m_frame->LogThreadMessage(text);
// write something to the text control }
void WriteText(const wxString& text);
public: public:
unsigned m_count; unsigned m_count;
@@ -205,12 +203,7 @@ MyThread::MyThread(MyFrame *frame)
m_frame = frame; m_frame = frame;
} }
void MyThread::WriteText(const wxString& text) MyThread::~MyThread()
{
m_frame->LogThreadMessage(text);
}
void MyThread::OnExit()
{ {
wxCriticalSectionLocker locker(wxGetApp().m_critsect); wxCriticalSectionLocker locker(wxGetApp().m_critsect);
@@ -221,9 +214,9 @@ void MyThread::OnExit()
{ {
// signal the main thread that there are no more threads left if it is // signal the main thread that there are no more threads left if it is
// waiting for us // waiting for us
if ( wxGetApp().m_waitingUntilAllDone ) if ( wxGetApp().m_shuttingDown )
{ {
wxGetApp().m_waitingUntilAllDone = false; wxGetApp().m_shuttingDown = false;
wxGetApp().m_semAllDone.Post(); wxGetApp().m_semAllDone.Post();
} }
@@ -241,7 +234,15 @@ void *MyThread::Entry()
for ( m_count = 0; m_count < 10; m_count++ ) for ( m_count = 0; m_count < 10; m_count++ )
{ {
// check if we were asked to exit // check if the application is shutting down: in this case all threads
// should stop a.s.a.p.
{
wxCriticalSectionLocker locker(wxGetApp().m_critsect);
if ( wxGetApp().m_shuttingDown )
return NULL;
}
// check if just this thread was asked to exit
if ( TestDestroy() ) if ( TestDestroy() )
break; break;
@@ -365,9 +366,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
END_EVENT_TABLE() END_EVENT_TABLE()
MyApp::MyApp() MyApp::MyApp()
: m_semAllDone()
{ {
m_waitingUntilAllDone = false; m_shuttingDown = false;
} }
// `Main program' equivalent, creating windows and returning main app frame // `Main program' equivalent, creating windows and returning main app frame
@@ -454,40 +454,23 @@ MyFrame::~MyFrame()
// tell all the threads to terminate: note that they can't terminate while // tell all the threads to terminate: note that they can't terminate while
// we're deleting them because they will block in their OnExit() -- this is // we're deleting them because they will block in their OnExit() -- this is
// important as otherwise we might access invalid array elements // important as otherwise we might access invalid array elements
wxThread *thread;
wxGetApp().m_critsect.Enter();
// check if we have any threads running first
const wxArrayThread& threads = wxGetApp().m_threads;
size_t count = threads.GetCount();
if ( count )
{ {
// set the flag for MyThread::OnExit() wxCriticalSectionLocker locker(wxGetApp().m_critsect);
wxGetApp().m_waitingUntilAllDone = true;
// stop all threads // check if we have any threads running first
while ( ! threads.IsEmpty() ) const wxArrayThread& threads = wxGetApp().m_threads;
{ size_t count = threads.GetCount();
thread = threads.Last();
wxGetApp().m_critsect.Leave(); if ( !count )
return;
thread->Delete(); // set the flag indicating that all threads should exit
wxGetApp().m_shuttingDown = true;
wxGetApp().m_critsect.Enter();
}
} }
wxGetApp().m_critsect.Leave(); // now wait for them to really terminate
wxGetApp().m_semAllDone.Wait();
if ( count )
{
// now wait for them to really terminate
wxGetApp().m_semAllDone.Wait();
}
//else: no threads to terminate, no condition to wait for
} }
MyThread *MyFrame::CreateThread() MyThread *MyFrame::CreateThread()
@@ -569,28 +552,19 @@ void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
{ {
wxGetApp().m_critsect.Enter(); wxCriticalSectionLocker enter(wxGetApp().m_critsect);
// stop the last thread // stop the last thread
if ( wxGetApp().m_threads.IsEmpty() ) if ( wxGetApp().m_threads.IsEmpty() )
{ {
wxLogError(wxT("No thread to stop!")); wxLogError(wxT("No thread to stop!"));
wxGetApp().m_critsect.Leave();
} }
else else
{ {
wxThread *thread = wxGetApp().m_threads.Last(); wxGetApp().m_threads.Last()->Delete();
// it's important to leave critical section before calling Delete()
// because delete will (implicitly) call OnExit() which also tries
// to enter the same crit section - would dead lock.
wxGetApp().m_critsect.Leave();
thread->Delete();
#if wxUSE_STATUSBAR #if wxUSE_STATUSBAR
SetStatusText(_T("Thread stopped."), 1); SetStatusText(_T("Last thread stopped."), 1);
#endif // wxUSE_STATUSBAR #endif // wxUSE_STATUSBAR
} }
} }