Commit 6c655274 authored by Davis King's avatar Davis King

Changed the thread_pool and future classes so that any mixture of

destruction orders between the two is legal.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403138
parent af20cb9f
...@@ -67,12 +67,13 @@ namespace ...@@ -67,12 +67,13 @@ namespace
void perform_test ( void perform_test (
) )
{ {
add_functor f;
for (int num_threads= 0; num_threads < 4; ++num_threads) for (int num_threads= 0; num_threads < 4; ++num_threads)
{ {
future<int> a, b, c, res;
thread_pool tp(num_threads); thread_pool tp(num_threads);
print_spinner(); print_spinner();
future<int> a, b, c, res;
future<some_struct> obj; future<some_struct> obj;
...@@ -205,12 +206,12 @@ namespace ...@@ -205,12 +206,12 @@ namespace
a = 1; a = 1;
b = 2; b = 2;
res = 0; res = 0;
add_functor f;
tp.add_task(f, a, b, res); tp.add_task(f, a, b, res);
DLIB_TEST(a == 1); DLIB_TEST(a == 1);
DLIB_TEST(b == 2); DLIB_TEST(b == 2);
DLIB_TEST(res == 3); DLIB_TEST(res == 3);
global_var = 0; global_var = 0;
DLIB_TEST(global_var == 0); DLIB_TEST(global_var == 0);
id = tp.add_task(&set_global_var); id = tp.add_task(&set_global_var);
...@@ -239,6 +240,9 @@ namespace ...@@ -239,6 +240,9 @@ namespace
} }
// add this task just to to perterb the thread pool before it goes out of scope
tp.add_task(f, a, b, res);
} }
} }
......
...@@ -10,8 +10,8 @@ namespace dlib ...@@ -10,8 +10,8 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
thread_pool:: thread_pool_implementation::
thread_pool ( thread_pool_implementation (
unsigned long num_threads unsigned long num_threads
) : ) :
task_done_signaler(m), task_done_signaler(m),
...@@ -21,7 +21,7 @@ namespace dlib ...@@ -21,7 +21,7 @@ namespace dlib
tasks.resize(num_threads); tasks.resize(num_threads);
for (unsigned long i = 0; i < num_threads; ++i) for (unsigned long i = 0; i < num_threads; ++i)
{ {
register_thread(*this, &thread_pool::thread); register_thread(*this, &thread_pool_implementation::thread);
} }
start(); start();
...@@ -29,10 +29,33 @@ namespace dlib ...@@ -29,10 +29,33 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
thread_pool:: void thread_pool_implementation::
~thread_pool() shutdown_pool (
)
{ {
{auto_mutex M(m); {
auto_mutex M(m);
// first wait for all pending tasks to finish
bool found_task = true;
while (found_task)
{
found_task = false;
for (unsigned long i = 0; i < tasks.size(); ++i)
{
// If task bucket i has a task that is currently supposed to be processed
if (tasks[i].is_empty() == false)
{
found_task = true;
break;
}
}
if (found_task)
task_done_signaler.wait();
}
// now tell the threads to kill themselves
we_are_destructing = true; we_are_destructing = true;
task_ready_signaler.broadcast(); task_ready_signaler.broadcast();
} }
...@@ -42,7 +65,15 @@ namespace dlib ...@@ -42,7 +65,15 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
unsigned long thread_pool:: thread_pool_implementation::
~thread_pool_implementation()
{
shutdown_pool();
}
// ----------------------------------------------------------------------------------------
unsigned long thread_pool_implementation::
num_threads_in_pool ( num_threads_in_pool (
) const ) const
{ {
...@@ -52,7 +83,7 @@ namespace dlib ...@@ -52,7 +83,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void thread_pool:: void thread_pool_implementation::
wait_for_task ( wait_for_task (
uint64 task_id uint64 task_id
) const ) const
...@@ -68,7 +99,7 @@ namespace dlib ...@@ -68,7 +99,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void thread_pool:: void thread_pool_implementation::
wait_for_all_tasks ( wait_for_all_tasks (
) const ) const
{ {
...@@ -97,7 +128,7 @@ namespace dlib ...@@ -97,7 +128,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
bool thread_pool:: bool thread_pool_implementation::
is_worker_thread ( is_worker_thread (
const thread_id_type id const thread_id_type id
) const ) const
...@@ -118,7 +149,7 @@ namespace dlib ...@@ -118,7 +149,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
void thread_pool:: void thread_pool_implementation::
thread ( thread (
) )
{ {
...@@ -175,7 +206,7 @@ namespace dlib ...@@ -175,7 +206,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
long thread_pool:: long thread_pool_implementation::
find_empty_task_slot ( find_empty_task_slot (
) const ) const
{ {
...@@ -190,7 +221,7 @@ namespace dlib ...@@ -190,7 +221,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
long thread_pool:: long thread_pool_implementation::
find_ready_task ( find_ready_task (
) const ) const
{ {
...@@ -205,7 +236,7 @@ namespace dlib ...@@ -205,7 +236,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
uint64 thread_pool:: uint64 thread_pool_implementation::
make_next_task_id ( make_next_task_id (
long idx long idx
) )
...@@ -217,7 +248,7 @@ namespace dlib ...@@ -217,7 +248,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
unsigned long thread_pool:: unsigned long thread_pool_implementation::
task_id_to_index ( task_id_to_index (
uint64 id uint64 id
) const ) const
...@@ -227,7 +258,7 @@ namespace dlib ...@@ -227,7 +258,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
uint64 thread_pool:: uint64 thread_pool_implementation::
add_task_internal ( add_task_internal (
const bfp_type& bfp const bfp_type& bfp
) )
...@@ -270,7 +301,7 @@ namespace dlib ...@@ -270,7 +301,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
bool thread_pool:: bool thread_pool_implementation::
is_task_thread ( is_task_thread (
) const ) const
{ {
......
This diff is collapsed.
...@@ -76,11 +76,6 @@ namespace dlib ...@@ -76,11 +76,6 @@ namespace dlib
~future ( ~future (
); );
/*! /*!
requires
- if (item.is_ready() == false) then
- The thread_pool that this future was passed to should still exist
(i.e. You can't pass a future to a thread_pool and then destruct the
thread_pool before you destruct the future).
ensures ensures
- if (item.is_ready() == false) then - if (item.is_ready() == false) then
- the call to this function blocks until the thread processing the task related - the call to this function blocks until the thread processing the task related
...@@ -223,6 +218,12 @@ namespace dlib ...@@ -223,6 +218,12 @@ namespace dlib
mode any thread that calls add_task() is considered to be mode any thread that calls add_task() is considered to be
a thread_pool thread capable of executing tasks. a thread_pool thread capable of executing tasks.
Also note that all function objects are passed to the tasks
by reference. This means you should ensure that your function
objects are not destroyed while tasks are still using them.
(e.g. Don't let them go out of scope right after a call to
add_task())
EXCEPTIONS EXCEPTIONS
Note that if an exception is thrown inside a task thread and Note that if an exception is thrown inside a task thread and
is not caught then the normal rule for uncaught exceptions in is not caught then the normal rule for uncaught exceptions in
...@@ -248,7 +249,7 @@ namespace dlib ...@@ -248,7 +249,7 @@ namespace dlib
); );
/*! /*!
ensures ensures
- all resources allocated by *this have been freed. - blocks until all tasks in the pool have finished.
!*/ !*/
bool is_task_thread ( bool is_task_thread (
......
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