Commit 5cc62847 authored by Davis King's avatar Davis King

- Added a bool to protect the unregister_thread_end_handler() function from

    being called from the destructor of a global object when the state object
    the unregister_thread_end_handler() function uses has already been destroyed.
  - Changed the thread pool so that it only gets destroyed if there aren't any
    outstanding threads when the program ends.  If there are threads still
    running user tasks then the thread pool never attempts to destruct.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402860
parent e2ea265f
......@@ -25,6 +25,10 @@ namespace dlib
namespace threads_kernel_shared
{
bool thread_pool_has_been_destroyed = false;
// ----------------------------------------------------------------------------------------
threader& thread_pool (
)
{
......@@ -40,7 +44,7 @@ namespace dlib
// global objects start to be destroyed
~threader_destruct_helper()
{
thread_pool().destruct_when_ready();
thread_pool().destruct_if_ready();
}
};
static threader_destruct_helper a;
......@@ -67,8 +71,7 @@ namespace dlib
data_ready(data_mutex),
data_empty(data_mutex),
destruct(false),
destructed(data_mutex),
should_destruct(false)
destructed(data_mutex)
{}
// ----------------------------------------------------------------------------------------
......@@ -84,13 +87,15 @@ namespace dlib
// wait for all the threads to end
while (total_count > 0)
destructed.wait();
thread_pool_has_been_destroyed = true;
data_mutex.unlock();
}
// ----------------------------------------------------------------------------------------
void threader::
destruct_when_ready (
destruct_if_ready (
)
{
data_mutex.lock();
......@@ -99,16 +104,10 @@ namespace dlib
// in the pool then just destroy the threader
if (total_count == pool_count)
{
data_mutex.unlock();
delete this;
}
else
{
// in this case we just let the thread pool know that it
// should self destruct whenever it gets a chance
should_destruct = true;
destruct = true;
data_ready.broadcast();
data_mutex.unlock();
delete this;
}
}
......@@ -198,7 +197,6 @@ namespace dlib
// get a reference to the calling threader object
threader& self = *reinterpret_cast<threader*>(object);
bool should_destroy_threader = false;
{
auto_mutex M(self.data_mutex);
......@@ -210,7 +208,7 @@ namespace dlib
// indicate that this thread is now in the thread pool
++self.pool_count;
while (true)
while (self.destruct == false)
{
// if data is ready then process it and launch the thread
// if its not ready then go back into the pool
......@@ -264,7 +262,7 @@ namespace dlib
++self.pool_count;
}
if (self.destruct == true || self.should_destruct == true)
if (self.destruct == true)
break;
// if we timed out and there isn't any work to do then
......@@ -285,13 +283,7 @@ namespace dlib
self.destructed.signal();
if (self.should_destruct && self.total_count == 0)
should_destroy_threader = true;
} // end of auto_mutex M(self.data_mutex) block
if (should_destroy_threader)
delete &self;
}
// ------------------------------------------------------------------------------------
......
......@@ -34,7 +34,6 @@ namespace dlib
- destructed is associated with the mutex data_mutex
- destruct == false
- total_count == 0
- should_destruct == false
- function_pointer == 0
CONVENTION
......@@ -60,11 +59,6 @@ namespace dlib
- thread_ids is locked by the data_mutex
- thread_ids == a set that contains the thread id for each thread spawned by this
object.
- if (destruct_when_ready() has been called) then
- should_destruct == true
- else
- should_destruct == false
!*/
......@@ -75,15 +69,14 @@ namespace dlib
~threader (
);
void destruct_when_ready (
void destruct_if_ready (
);
/*!
ensures
- if (there are no threads currently running) then
- calls delete this
- else
- sets a flag that will cause the last thread to
call delete this when it finishes
- does nothing
!*/
bool create_new_thread (
......@@ -163,7 +156,6 @@ namespace dlib
signaler data_empty; // signaler to signal when the data is empty
bool destruct;
signaler destructed; // signaler to signal when a thread has ended
bool should_destruct;
struct registry_type
{
......@@ -196,6 +188,7 @@ namespace dlib
// ------------------------------------------------------------------------------------
extern bool thread_pool_has_been_destroyed;
}
bool is_dlib_thread (
......@@ -251,7 +244,14 @@ namespace dlib
void (T::*handler)()
)
{
threads_kernel_shared::thread_pool().unregister_thread_end_handler(obj,handler);
// Check if the thread pool has been destroyed and if it has then don't do anything.
// This bool here is always true except when the program has started to terminate and
// the thread pool object has been destroyed. This if is here to catch other global
// objects that have destructors that try to call unregister_thread_end_handler().
// Without this check we get into trouble if the thread pool is destroyed before these
// objects.
if (threads_kernel_shared::thread_pool_has_been_destroyed == false)
threads_kernel_shared::thread_pool().unregister_thread_end_handler(obj,handler);
}
// ----------------------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment