fix the examples for wxThread and wxThreadHelper after field-testing on wxMSW and wxGTK; add a note to wxThread::Run about detached threads; fix the note for wxThread::Delete wrt joinable threads
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@56960 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -279,59 +279,121 @@ public:
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
@code
|
@code
|
||||||
|
extern const wxEventType wxEVT_COMMAND_MYTHREAD_UPDATE;
|
||||||
|
|
||||||
class MyFrame : public wxFrame, public wxThreadHelper
|
class MyFrame : public wxFrame, public wxThreadHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MyFrame() : wxThreadHelper(wxTHREAD_JOINABLE) {}
|
MyFrame(...) { ... }
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
virtual ExitCode Entry()
|
|
||||||
{
|
|
||||||
// here we do our long task, periodically calling TestDestroy():
|
|
||||||
while (!TestDestroy())
|
|
||||||
{
|
|
||||||
// ...do another bit of work here...
|
|
||||||
|
|
||||||
// post an update message to the frame
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestDestroy() returned true (which means the main thread
|
|
||||||
// asked us to terminate as soon as possible) or we ended the
|
|
||||||
// long task...
|
|
||||||
return (ExitCode)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~MyFrame()
|
~MyFrame()
|
||||||
{
|
{
|
||||||
// important: before terminating, we _must_ wait for our
|
// it's better to do any thread cleanup in the OnClose()
|
||||||
// joinable thread to end, if it's running!
|
// event handler, rather than in the destructor.
|
||||||
if (GetThread()->IsRunning())
|
// This is because the event loop for a top-level window is not
|
||||||
GetThread()->Wait();
|
// active anymore when its destructor is called and if the thread
|
||||||
|
// sends events when ending, they won't be processed unless
|
||||||
|
// you ended the thread from OnClose.
|
||||||
|
// See @ref overview_windowdeletion for more info.
|
||||||
}
|
}
|
||||||
|
|
||||||
...
|
...
|
||||||
void DoStartALongTask();
|
void DoStartALongTask();
|
||||||
|
void OnThreadUpdate(wxCommandEvent& evt);
|
||||||
|
void OnClose(wxCloseEvent& evt);
|
||||||
...
|
...
|
||||||
}
|
|
||||||
|
protected:
|
||||||
|
virtual wxThread::ExitCode Entry();
|
||||||
|
|
||||||
|
// the output data of the Entry() routine:
|
||||||
|
char m_data[1024];
|
||||||
|
wxCriticalSection m_dataCS; // protects field above
|
||||||
|
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_UPDATE)
|
||||||
|
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
||||||
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
|
||||||
|
EVT_CLOSE(MyFrame::OnClose)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
void MyFrame::DoStartALongTask()
|
void MyFrame::DoStartALongTask()
|
||||||
{
|
{
|
||||||
// we want to start a long task, but we don't want our GUI to block
|
// we want to start a long task, but we don't want our GUI to block
|
||||||
// while it's executed, so we use a thread to do it.
|
// while it's executed, so we use a thread to do it.
|
||||||
if (Create() != wxTHREAD_NO_ERROR)
|
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR)
|
||||||
{
|
{
|
||||||
wxLogError("Could not create the worker thread!");
|
wxLogError("Could not create the worker thread!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// go!
|
// go!
|
||||||
if (Run() != wxTHREAD_NO_ERROR)
|
if (GetThread()->Run() != wxTHREAD_NO_ERROR)
|
||||||
{
|
{
|
||||||
wxLogError("Could not run the worker thread!");
|
wxLogError("Could not run the worker thread!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxThread::ExitCode MyFrame::Entry()
|
||||||
|
{
|
||||||
|
// IMPORTANT:
|
||||||
|
// this function gets executed in the secondary thread context!
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// here we do our long task, periodically calling TestDestroy():
|
||||||
|
while (!GetThread()->TestDestroy())
|
||||||
|
{
|
||||||
|
// since this Entry() is implemented in MyFrame context we don't
|
||||||
|
// need any pointer to access the m_data, m_processedData, m_dataCS
|
||||||
|
// variables... very nice!
|
||||||
|
|
||||||
|
// this is an example of the generic structure of a download thread:
|
||||||
|
char buffer[1024];
|
||||||
|
download_chunk(buffer, 1024); // this takes time...
|
||||||
|
|
||||||
|
{
|
||||||
|
// ensure noone reads m_data while we write it
|
||||||
|
wxCriticalSectionLocker lock(m_dataCS);
|
||||||
|
memcpy(m_data+offset, buffer, 1024);
|
||||||
|
offset += 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// VERY IMPORTANT: do not call any GUI function inside this
|
||||||
|
// function; rather use wxQueueEvent():
|
||||||
|
wxQueueEvent(this, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
|
||||||
|
// we used pointer 'this' assuming it's safe; see OnClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDestroy() returned true (which means the main thread asked us
|
||||||
|
// to terminate as soon as possible) or we ended the long task...
|
||||||
|
return (wxThread::ExitCode)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::OnClose(wxCloseEvent&)
|
||||||
|
{
|
||||||
|
// important: before terminating, we _must_ wait for our joinable
|
||||||
|
// thread to end, if it's running; in fact it uses variables of this
|
||||||
|
// instance and posts events to *this event handler
|
||||||
|
|
||||||
|
if (GetThread() && // DoStartALongTask() may have not been called
|
||||||
|
GetThread()->IsRunning())
|
||||||
|
GetThread()->Wait();
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::OnThreadUpdate(wxCommandEvent&evt)
|
||||||
|
{
|
||||||
|
// ...do something... e.g. m_pGauge->Pulse();
|
||||||
|
|
||||||
|
// read some parts of m_data just for fun:
|
||||||
|
wxCriticalSectionLocker lock(m_dataCS);
|
||||||
|
wxPrintf("%c", m_data[100]);
|
||||||
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@library{wxbase}
|
@library{wxbase}
|
||||||
@@ -365,6 +427,25 @@ public:
|
|||||||
This function is pure virtual and must be implemented by any derived class.
|
This function is pure virtual and must be implemented by any derived class.
|
||||||
The thread execution will start here.
|
The thread execution will start here.
|
||||||
|
|
||||||
|
You'll typically want your Entry() to look like:
|
||||||
|
@code
|
||||||
|
wxThread::ExitCode Entry()
|
||||||
|
{
|
||||||
|
while (!GetThread()->TestDestroy())
|
||||||
|
{
|
||||||
|
// ... do some work ...
|
||||||
|
|
||||||
|
if (IsWorkCompleted)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (HappenedStoppingError)
|
||||||
|
return (wxThread::ExitCode)1; // failure
|
||||||
|
}
|
||||||
|
|
||||||
|
return (wxThread::ExitCode)0; // success
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
The returned value is the thread exit code which is only useful for
|
The returned value is the thread exit code which is only useful for
|
||||||
joinable threads and is the value returned by @c "GetThread()->Wait()".
|
joinable threads and is the value returned by @c "GetThread()->Wait()".
|
||||||
|
|
||||||
@@ -374,26 +455,30 @@ public:
|
|||||||
virtual ExitCode Entry() = 0;
|
virtual ExitCode Entry() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a new thread.
|
Creates a new thread of the given @a kind.
|
||||||
|
|
||||||
The thread object is created in the suspended state, and you
|
The thread object is created in the suspended state, and you
|
||||||
should call @ref wxThread::Run "GetThread()->Run()" to start running it.
|
should call @ref wxThread::Run "GetThread()->Run()" to start running it.
|
||||||
|
|
||||||
You may optionally specify the stack size to be allocated to it (ignored
|
You may optionally specify the stack size to be allocated to it (ignored
|
||||||
on platforms that don't support setting it explicitly, eg. Unix).
|
on platforms that don't support setting it explicitly, e.g. Unix).
|
||||||
|
|
||||||
Note that the type of the thread which is created is defined in the
|
|
||||||
constructor.
|
|
||||||
|
|
||||||
@return One of the ::wxThreadError enum values.
|
@return One of the ::wxThreadError enum values.
|
||||||
*/
|
*/
|
||||||
wxThreadError Create(unsigned int stackSize = 0);
|
wxThreadError CreateThread(wxThreadKind kind = wxTHREAD_JOINABLE,
|
||||||
|
unsigned int stackSize = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This is a public function that returns the wxThread object associated with
|
This is a public function that returns the wxThread object associated with
|
||||||
the thread.
|
the thread.
|
||||||
*/
|
*/
|
||||||
wxThread* GetThread() const;
|
wxThread* GetThread() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the last type of thread given to the CreateThread() function
|
||||||
|
or to the constructor.
|
||||||
|
*/
|
||||||
|
wxThreadKind GetThreadKind() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -541,55 +626,66 @@ enum
|
|||||||
@code
|
@code
|
||||||
// declare a new type of event, to be used by our MyThread class:
|
// declare a new type of event, to be used by our MyThread class:
|
||||||
extern const wxEventType wxEVT_COMMAND_MYTHREAD_COMPLETED;
|
extern const wxEventType wxEVT_COMMAND_MYTHREAD_COMPLETED;
|
||||||
|
extern const wxEventType wxEVT_COMMAND_MYTHREAD_UPDATE;
|
||||||
|
class MyFrame;
|
||||||
|
|
||||||
class MyThread : public wxThread
|
class MyThread : public wxThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MyThread(wxEvtHandler *handler) : wxThread(wxTHREAD_DETACHED)
|
MyThread(MyFrame *handler)
|
||||||
{ m_pHandler = handler; }
|
: wxThread(wxTHREAD_DETACHED)
|
||||||
|
{ m_pHandler = handler }
|
||||||
|
~MyThread();
|
||||||
|
|
||||||
ExitCode Entry()
|
protected:
|
||||||
{
|
virtual ExitCode Entry();
|
||||||
while (!TestDestroy())
|
MyFrame *m_pHandler;
|
||||||
{
|
|
||||||
// ... do a bit of work...
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal the event handler that this thread is going to be destroyed
|
|
||||||
// NOTE: here we assume that using the m_pHandler pointer is safe,
|
|
||||||
// (in this case it's assured by the MyFrame destructor)
|
|
||||||
wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
|
|
||||||
|
|
||||||
return (ExitCode)0; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
wxEvtHandler *m_pHandler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MyFrame : public wxFrame
|
class MyFrame : public wxFrame
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
...
|
...
|
||||||
~MyFrame();
|
~MyFrame()
|
||||||
|
{
|
||||||
|
// it's better to do any thread cleanup in the OnClose()
|
||||||
|
// event handler, rather than in the destructor.
|
||||||
|
// This is because the event loop for a top-level window is not
|
||||||
|
// active anymore when its destructor is called and if the thread
|
||||||
|
// sends events when ending, they won't be processed unless
|
||||||
|
// you ended the thread from OnClose.
|
||||||
|
// See @ref overview_windowdeletion for more info.
|
||||||
|
}
|
||||||
...
|
...
|
||||||
void DoStartThread();
|
void DoStartThread();
|
||||||
void DoPauseThread();
|
void DoPauseThread();
|
||||||
|
|
||||||
// a resume routine would be mostly identic to DoPauseThread()
|
// a resume routine would be nearly identic to DoPauseThread()
|
||||||
void DoResumeThread() { ... }
|
void DoResumeThread() { ... }
|
||||||
|
|
||||||
void OnThreadExit(wxCommandEvent&);
|
void OnThreadCompletion(wxCommandEvent&);
|
||||||
|
void OnClose(wxCloseEvent&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MyThread *m_pThread;
|
MyThread *m_pThread;
|
||||||
|
wxCriticalSection m_pThreadCS; // protects the m_pThread pointer
|
||||||
|
|
||||||
// this is _required_ for writing safe code!
|
DECLARE_EVENT_TABLE()
|
||||||
wxCriticalSection m_critSection;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
||||||
|
EVT_CLOSE(MyFrame::OnClose)
|
||||||
|
EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
|
||||||
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
|
||||||
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_COMPLETED)
|
||||||
|
DEFINE_EVENT_TYPE(wxEVT_COMMAND_MYTHREAD_UPDATE)
|
||||||
|
|
||||||
void MyFrame::DoStartThread()
|
void MyFrame::DoStartThread()
|
||||||
{
|
{
|
||||||
m_pThread = new wxThread();
|
m_pThread = new MyThread(this);
|
||||||
|
|
||||||
if ( m_pThread->Create() != wxTHREAD_NO_ERROR )
|
if ( m_pThread->Create() != wxTHREAD_NO_ERROR )
|
||||||
{
|
{
|
||||||
@@ -613,55 +709,96 @@ enum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyFrame::OnThreadExit(wxCommandEvent&)
|
wxThread::ExitCode MyThread::Entry()
|
||||||
{
|
{
|
||||||
// the thread just ended; make sure not to leave dangling pointers around
|
while (!TestDestroy())
|
||||||
m_pThread = NULL;
|
{
|
||||||
|
// ... do a bit of work...
|
||||||
|
|
||||||
|
wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal the event handler that this thread is going to be destroyed
|
||||||
|
// NOTE: here we assume that using the m_pHandler pointer is safe,
|
||||||
|
// (in this case this is assured by the MyFrame destructor)
|
||||||
|
wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
|
||||||
|
|
||||||
|
return (wxThread::ExitCode)0; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
MyThread::~MyThread()
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
|
||||||
|
|
||||||
|
// the thread is being destroyed; make sure not to leave dangling pointers around
|
||||||
|
m_pHandler->m_pThread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::OnThreadCompletion(wxCommandEvent&)
|
||||||
|
{
|
||||||
|
wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::OnThreadUpdate(wxCommandEvent&)
|
||||||
|
{
|
||||||
|
wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyFrame::DoPauseThread()
|
void MyFrame::DoPauseThread()
|
||||||
{
|
{
|
||||||
// anytime we access the m_pThread pointer we must ensure that it won't
|
// anytime we access the m_pThread pointer we must ensure that it won't
|
||||||
// be modified in the meanwhile; inside a critical section we are sure
|
// be modified in the meanwhile; since only a single thread may be
|
||||||
// that we are the only thread running, so that's what we need.
|
// inside a given critical section at a given time, the following code
|
||||||
wxCriticalSectionLocker enter(m_critSection);
|
// is safe:
|
||||||
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
||||||
|
|
||||||
if (m_pThread) // does the thread still exist?
|
if (m_pThread) // does the thread still exist?
|
||||||
{
|
{
|
||||||
// without a critical section, once reached this point it may happen
|
// without a critical section, once reached this point it may happen
|
||||||
// that the OS scheduler gives control to the MyThread::Entry() function,
|
// that the OS scheduler gives control to the MyThread::Entry() function,
|
||||||
// which in turn may return (because it completes its work) making
|
// which in turn may return (because it completes its work) making
|
||||||
// invalid the m_pThread pointer; the critical section above
|
// invalid the m_pThread pointer
|
||||||
// makes this code safe.
|
|
||||||
|
|
||||||
if (m_pThread->Pause() != wxTHREAD_NO_ERROR )
|
if (m_pThread->Pause() != wxTHREAD_NO_ERROR )
|
||||||
wxLogError("Can't pause the thread!");
|
wxLogError("Can't pause the thread!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MyFrame::~MyFrame()
|
void MyFrame::OnClose(wxCloseEvent&)
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker enter(m_critSection);
|
{
|
||||||
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
||||||
|
|
||||||
if (m_pThread) // does the thread still exist?
|
if (m_pThread) // does the thread still exist?
|
||||||
{
|
{
|
||||||
|
m_out.Printf("MYFRAME: deleting thread");
|
||||||
|
|
||||||
if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
|
if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
|
||||||
wxLogError("Can't delete the thread!");
|
wxLogError("Can't delete the thread!");
|
||||||
|
|
||||||
// as soon as we exit the critical section and the MyThread::Entry
|
|
||||||
// function calls TestDestroy(), the thread will exit and thus
|
|
||||||
// call OnExitThread(); we need to maintain MyFrame object alive
|
|
||||||
// until then:
|
|
||||||
wxEventLoopBase* p = wxEventLoopBase::GetActive();
|
|
||||||
while (p->Pending() && m_pThread)
|
|
||||||
p->Dispatch();
|
|
||||||
|
|
||||||
// the wxEVT_COMMAND_MYTHREAD_COMPLETED event was posted, we can
|
|
||||||
// safely exit
|
|
||||||
}
|
}
|
||||||
|
} // exit from the critical section to give the thread
|
||||||
|
// the possibility to enter its destructor
|
||||||
|
// (which is guarded with m_pThreadCS critical section!)
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
{ // was the ~MyThread() function executed?
|
||||||
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
||||||
|
if (!m_pThread) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for thread completion
|
||||||
|
wxThread::This()->Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Destroy();
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
For a more detailed and comprehensive example, see @sample{thread}.
|
||||||
|
For a simpler way to share data and synchronization objects between
|
||||||
|
the main and the secondary thread see wxThreadHelper.
|
||||||
|
|
||||||
Conversely, @b joinable threads do not delete themselves when they are done
|
Conversely, @b joinable threads do not delete themselves when they are done
|
||||||
processing and as such are safe to create on the stack. Joinable threads
|
processing and as such are safe to create on the stack. Joinable threads
|
||||||
also provide the ability for one to get value it returned from Entry()
|
also provide the ability for one to get value it returned from Entry()
|
||||||
@@ -817,9 +954,10 @@ public:
|
|||||||
the thread calls TestDestroy() or when it finishes processing.
|
the thread calls TestDestroy() or when it finishes processing.
|
||||||
|
|
||||||
@note
|
@note
|
||||||
While this could work on a joinable thread you simply should not
|
This function works on a joinable thread but in that case makes
|
||||||
call this routine on them as afterwards you may not be able to call
|
the TestDestroy() function of the thread return @true and then
|
||||||
Wait() to free the memory of that thread.
|
waits for its completion (i.e. it differs from Wait() because
|
||||||
|
it asks the thread to terminate before waiting).
|
||||||
|
|
||||||
See @ref thread_deletion for a broader explanation of this routine.
|
See @ref thread_deletion for a broader explanation of this routine.
|
||||||
*/
|
*/
|
||||||
@@ -944,8 +1082,13 @@ public:
|
|||||||
wxThreadError Resume();
|
wxThreadError Resume();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Starts the thread execution. Should be called after
|
Starts the thread execution. Should be called after Create().
|
||||||
Create().
|
|
||||||
|
Note that once you Run() a @b detached thread, @e any function call you do
|
||||||
|
on the thread pointer (you must allocate it on the heap) is @e "unsafe";
|
||||||
|
i.e. the thread may have terminated at any moment after Run() and your pointer
|
||||||
|
may be dangling. See @ref thread_types for an example of safe manipulation
|
||||||
|
of detached threads.
|
||||||
|
|
||||||
This function can only be called from another thread context.
|
This function can only be called from another thread context.
|
||||||
*/
|
*/
|
||||||
@@ -1003,12 +1146,13 @@ public:
|
|||||||
static wxThread* This();
|
static wxThread* This();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Waits for a joinable thread to terminate and returns the value the thread
|
Waits for a @b joinable thread to terminate and returns the value the thread
|
||||||
returned from Entry() or @c "(ExitCode)-1" on error. Notice that, unlike
|
returned from Entry() or @c "(ExitCode)-1" on error. Notice that, unlike
|
||||||
Delete(), this function doesn't cancel the thread in any way so the caller
|
Delete(), this function doesn't cancel the thread in any way so the caller
|
||||||
waits for as long as it takes to the thread to exit.
|
waits for as long as it takes to the thread to exit.
|
||||||
|
|
||||||
You can only Wait() for @b joinable (not detached) threads.
|
You can only Wait() for @b joinable (not detached) threads.
|
||||||
|
|
||||||
This function can only be called from another thread context.
|
This function can only be called from another thread context.
|
||||||
|
|
||||||
See @ref thread_deletion for a broader explanation of this routine.
|
See @ref thread_deletion for a broader explanation of this routine.
|
||||||
@@ -1016,7 +1160,7 @@ public:
|
|||||||
ExitCode Wait();
|
ExitCode Wait();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Give the rest of the thread time slice to the system allowing the other
|
Give the rest of the thread's time-slice to the system allowing the other
|
||||||
threads to run.
|
threads to run.
|
||||||
|
|
||||||
Note that using this function is @b strongly discouraged, since in
|
Note that using this function is @b strongly discouraged, since in
|
||||||
@@ -1042,8 +1186,8 @@ public:
|
|||||||
With a well-behaving, CPU-efficient thread the operating system is likely
|
With a well-behaving, CPU-efficient thread the operating system is likely
|
||||||
to properly care for its reactivation the moment it needs it, whereas with
|
to properly care for its reactivation the moment it needs it, whereas with
|
||||||
non-deterministic, Yield-using threads all bets are off and the system
|
non-deterministic, Yield-using threads all bets are off and the system
|
||||||
scheduler is free to penalize drastically</strong>, and this effect gets worse
|
scheduler is free to penalize them drastically</strong>, and this effect
|
||||||
with increasing system load due to less free CPU resources available.
|
gets worse with increasing system load due to less free CPU resources available.
|
||||||
You may refer to various Linux kernel @c sched_yield discussions for more
|
You may refer to various Linux kernel @c sched_yield discussions for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user