no real change; just reorder the sample putting all declarations together and all implementations together; move frame construction code in MyFrame ctor; add some comment about TEST_YIELD_RACE_CONDITIONsymbol
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59052 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -9,6 +9,14 @@
|
|||||||
// Licence: wxWindows license
|
// Licence: wxWindows license
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// declarations
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// headers
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// For compilers that support precompilation, includes "wx/wx.h".
|
// For compilers that support precompilation, includes "wx/wx.h".
|
||||||
#include "wx/wxprec.h"
|
#include "wx/wxprec.h"
|
||||||
|
|
||||||
@@ -27,11 +35,18 @@
|
|||||||
#include "wx/thread.h"
|
#include "wx/thread.h"
|
||||||
#include "wx/dynarray.h"
|
#include "wx/dynarray.h"
|
||||||
#include "wx/numdlg.h"
|
#include "wx/numdlg.h"
|
||||||
|
|
||||||
#include "wx/progdlg.h"
|
#include "wx/progdlg.h"
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// resources
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "../sample.xpm"
|
#include "../sample.xpm"
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// private classes
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// define this to use wxExecute in the exec tests, otherwise just use system
|
// define this to use wxExecute in the exec tests, otherwise just use system
|
||||||
#define USE_EXECUTE
|
#define USE_EXECUTE
|
||||||
|
|
||||||
@@ -67,9 +82,6 @@ public:
|
|||||||
bool m_shuttingDown;
|
bool m_shuttingDown;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a new application object
|
|
||||||
IMPLEMENT_APP(MyApp)
|
|
||||||
|
|
||||||
// Define a new frame type
|
// Define a new frame type
|
||||||
class MyFrame: public wxFrame
|
class MyFrame: public wxFrame
|
||||||
{
|
{
|
||||||
@@ -150,6 +162,10 @@ private:
|
|||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// constants
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// ID for the menu commands
|
// ID for the menu commands
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -196,70 +212,6 @@ public:
|
|||||||
MyFrame *m_frame;
|
MyFrame *m_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
MyThread::MyThread(MyFrame *frame)
|
|
||||||
: wxThread()
|
|
||||||
{
|
|
||||||
m_count = 0;
|
|
||||||
m_frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
MyThread::~MyThread()
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker locker(wxGetApp().m_critsect);
|
|
||||||
|
|
||||||
wxArrayThread& threads = wxGetApp().m_threads;
|
|
||||||
threads.Remove(this);
|
|
||||||
|
|
||||||
if ( threads.IsEmpty() )
|
|
||||||
{
|
|
||||||
// signal the main thread that there are no more threads left if it is
|
|
||||||
// waiting for us
|
|
||||||
if ( wxGetApp().m_shuttingDown )
|
|
||||||
{
|
|
||||||
wxGetApp().m_shuttingDown = false;
|
|
||||||
|
|
||||||
wxGetApp().m_semAllDone.Post();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *MyThread::Entry()
|
|
||||||
{
|
|
||||||
wxString text;
|
|
||||||
|
|
||||||
text.Printf(wxT("Thread 0x%lx started (priority = %u).\n"),
|
|
||||||
GetId(), GetPriority());
|
|
||||||
WriteText(text);
|
|
||||||
// wxLogMessage(text); -- test wxLog thread safeness
|
|
||||||
|
|
||||||
for ( m_count = 0; m_count < 10; m_count++ )
|
|
||||||
{
|
|
||||||
// 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() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
text.Printf(wxT("[%u] Thread 0x%lx here.\n"), m_count, GetId());
|
|
||||||
WriteText(text);
|
|
||||||
|
|
||||||
// wxSleep() can't be called from non-GUI thread!
|
|
||||||
wxThread::Sleep(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
text.Printf(wxT("Thread 0x%lx finished.\n"), GetId());
|
|
||||||
WriteText(text);
|
|
||||||
// wxLogMessage(text); -- test wxLog thread safeness
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// worker thread
|
// worker thread
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -281,57 +233,6 @@ public:
|
|||||||
unsigned m_count;
|
unsigned m_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
MyWorkerThread::MyWorkerThread(MyFrame *frame)
|
|
||||||
: wxThread()
|
|
||||||
{
|
|
||||||
m_frame = frame;
|
|
||||||
m_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyWorkerThread::OnExit()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TEST_YIELD_RACE_CONDITION 0
|
|
||||||
|
|
||||||
void *MyWorkerThread::Entry()
|
|
||||||
{
|
|
||||||
#if TEST_YIELD_RACE_CONDITION
|
|
||||||
if ( TestDestroy() )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
|
||||||
|
|
||||||
event.SetInt( 50 );
|
|
||||||
wxQueueEvent( m_frame, new wxThreadEvent(event) );
|
|
||||||
|
|
||||||
event.SetInt(-1);
|
|
||||||
wxQueueEvent( m_frame, new wxThreadEvent(event) );
|
|
||||||
#else
|
|
||||||
for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
|
|
||||||
{
|
|
||||||
// check if we were asked to exit
|
|
||||||
if ( TestDestroy() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// create any type of command event here
|
|
||||||
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
|
||||||
event.SetInt( m_count );
|
|
||||||
|
|
||||||
// send in a thread-safe way
|
|
||||||
wxQueueEvent( m_frame, new wxThreadEvent(event) );
|
|
||||||
|
|
||||||
wxMilliSleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
|
||||||
event.SetInt(-1); // that's all
|
|
||||||
wxQueueEvent( m_frame, new wxThreadEvent(event) );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// a thread which simply calls wxExecute
|
// a thread which simply calls wxExecute
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -354,8 +255,45 @@ private:
|
|||||||
wxString m_command;
|
wxString m_command;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ============================================================================
|
||||||
// implementation
|
// implementation
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// the application class
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Create a new application object
|
||||||
|
IMPLEMENT_APP(MyApp)
|
||||||
|
|
||||||
|
MyApp::MyApp()
|
||||||
|
{
|
||||||
|
m_shuttingDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Main program' equivalent, creating windows and returning main app frame
|
||||||
|
bool MyApp::OnInit()
|
||||||
|
{
|
||||||
|
if ( !wxApp::OnInit() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// uncomment this to get some debugging messages from the trace code
|
||||||
|
// on the console (or just set WXTRACE env variable to include "thread")
|
||||||
|
//wxLog::AddTraceMask("thread");
|
||||||
|
|
||||||
|
// Create the main frame window
|
||||||
|
MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("wxWidgets threads sample"),
|
||||||
|
50, 50, 450, 340);
|
||||||
|
SetTopWindow(frame);
|
||||||
|
|
||||||
|
// Show the frame
|
||||||
|
frame->Show(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// MyFrame
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
||||||
@@ -381,24 +319,12 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
|||||||
EVT_IDLE(MyFrame::OnIdle)
|
EVT_IDLE(MyFrame::OnIdle)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
MyApp::MyApp()
|
// My frame constructor
|
||||||
|
MyFrame::MyFrame(wxFrame *frame, const wxString& title,
|
||||||
|
int x, int y, int w, int h)
|
||||||
|
: wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
|
||||||
{
|
{
|
||||||
m_shuttingDown = false;
|
SetIcon(wxIcon(sample_xpm));
|
||||||
}
|
|
||||||
|
|
||||||
// `Main program' equivalent, creating windows and returning main app frame
|
|
||||||
bool MyApp::OnInit()
|
|
||||||
{
|
|
||||||
if ( !wxApp::OnInit() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// uncomment this to get some debugging messages from the trace code
|
|
||||||
// on the console (or just set WXTRACE env variable to include "thread")
|
|
||||||
//wxLog::AddTraceMask("thread");
|
|
||||||
|
|
||||||
// Create the main frame window
|
|
||||||
MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("wxWidgets threads sample"),
|
|
||||||
50, 50, 450, 340);
|
|
||||||
|
|
||||||
// Make a menubar
|
// Make a menubar
|
||||||
wxMenuBar *menuBar = new wxMenuBar;
|
wxMenuBar *menuBar = new wxMenuBar;
|
||||||
@@ -431,22 +357,7 @@ bool MyApp::OnInit()
|
|||||||
menuHelp->Append(THREAD_ABOUT, _T("&About..."));
|
menuHelp->Append(THREAD_ABOUT, _T("&About..."));
|
||||||
menuBar->Append(menuHelp, _T("&Help"));
|
menuBar->Append(menuHelp, _T("&Help"));
|
||||||
|
|
||||||
frame->SetMenuBar(menuBar);
|
SetMenuBar(menuBar);
|
||||||
|
|
||||||
// Show the frame
|
|
||||||
frame->Show(true);
|
|
||||||
|
|
||||||
SetTopWindow(frame);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// My frame constructor
|
|
||||||
MyFrame::MyFrame(wxFrame *frame, const wxString& title,
|
|
||||||
int x, int y, int w, int h)
|
|
||||||
: wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
|
|
||||||
{
|
|
||||||
SetIcon(wxIcon(sample_xpm));
|
|
||||||
|
|
||||||
m_nRunning = m_nCount = 0;
|
m_nRunning = m_nCount = 0;
|
||||||
|
|
||||||
@@ -803,3 +714,133 @@ bool MyFrame::Cancelled()
|
|||||||
|
|
||||||
return m_cancelled;
|
return m_cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// MyThread
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
MyThread::MyThread(MyFrame *frame)
|
||||||
|
: wxThread()
|
||||||
|
{
|
||||||
|
m_count = 0;
|
||||||
|
m_frame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyThread::~MyThread()
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker locker(wxGetApp().m_critsect);
|
||||||
|
|
||||||
|
wxArrayThread& threads = wxGetApp().m_threads;
|
||||||
|
threads.Remove(this);
|
||||||
|
|
||||||
|
if ( threads.IsEmpty() )
|
||||||
|
{
|
||||||
|
// signal the main thread that there are no more threads left if it is
|
||||||
|
// waiting for us
|
||||||
|
if ( wxGetApp().m_shuttingDown )
|
||||||
|
{
|
||||||
|
wxGetApp().m_shuttingDown = false;
|
||||||
|
|
||||||
|
wxGetApp().m_semAllDone.Post();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MyThread::Entry()
|
||||||
|
{
|
||||||
|
wxString text;
|
||||||
|
|
||||||
|
text.Printf(wxT("Thread 0x%lx started (priority = %u).\n"),
|
||||||
|
GetId(), GetPriority());
|
||||||
|
WriteText(text);
|
||||||
|
// wxLogMessage(text); -- test wxLog thread safeness
|
||||||
|
|
||||||
|
for ( m_count = 0; m_count < 10; m_count++ )
|
||||||
|
{
|
||||||
|
// 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() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
text.Printf(wxT("[%u] Thread 0x%lx here.\n"), m_count, GetId());
|
||||||
|
WriteText(text);
|
||||||
|
|
||||||
|
// wxSleep() can't be called from non-GUI thread!
|
||||||
|
wxThread::Sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
text.Printf(wxT("Thread 0x%lx finished.\n"), GetId());
|
||||||
|
WriteText(text);
|
||||||
|
// wxLogMessage(text); -- test wxLog thread safeness
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// MyWorkerThread
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
MyWorkerThread::MyWorkerThread(MyFrame *frame)
|
||||||
|
: wxThread()
|
||||||
|
{
|
||||||
|
m_frame = frame;
|
||||||
|
m_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyWorkerThread::OnExit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update
|
||||||
|
// function provokes a race condition in which the second wxThreadEvent posted by
|
||||||
|
// MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update
|
||||||
|
// and results in the destruction of the progress dialog itself, resulting in a crash later.
|
||||||
|
#define TEST_YIELD_RACE_CONDITION 0
|
||||||
|
|
||||||
|
void *MyWorkerThread::Entry()
|
||||||
|
{
|
||||||
|
#if TEST_YIELD_RACE_CONDITION
|
||||||
|
if ( TestDestroy() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
||||||
|
|
||||||
|
event.SetInt( 50 );
|
||||||
|
wxQueueEvent( m_frame, event.Clone() );
|
||||||
|
|
||||||
|
event.SetInt(-1);
|
||||||
|
wxQueueEvent( m_frame, event.Clone() );
|
||||||
|
#else
|
||||||
|
for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
|
||||||
|
{
|
||||||
|
// check if we were asked to exit
|
||||||
|
if ( TestDestroy() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// create any type of command event here
|
||||||
|
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
||||||
|
event.SetInt( m_count );
|
||||||
|
|
||||||
|
// send in a thread-safe way
|
||||||
|
wxQueueEvent( m_frame, event.Clone() );
|
||||||
|
|
||||||
|
wxMilliSleep(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT );
|
||||||
|
event.SetInt(-1); // that's all
|
||||||
|
wxQueueEvent( m_frame, event.Clone() );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user