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
This commit is contained in:
Davis King 2009-07-19 15:06:05 +00:00
parent af20cb9f36
commit 6c65527410
4 changed files with 584 additions and 459 deletions

View File

@ -67,12 +67,13 @@ namespace
void perform_test (
)
{
add_functor f;
for (int num_threads= 0; num_threads < 4; ++num_threads)
{
future<int> a, b, c, res;
thread_pool tp(num_threads);
print_spinner();
future<int> a, b, c, res;
future<some_struct> obj;
@ -205,12 +206,12 @@ namespace
a = 1;
b = 2;
res = 0;
add_functor f;
tp.add_task(f, a, b, res);
DLIB_TEST(a == 1);
DLIB_TEST(b == 2);
DLIB_TEST(res == 3);
global_var = 0;
DLIB_TEST(global_var == 0);
id = tp.add_task(&set_global_var);
@ -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);
}
}

View File

@ -10,8 +10,8 @@ namespace dlib
// ----------------------------------------------------------------------------------------
thread_pool::
thread_pool (
thread_pool_implementation::
thread_pool_implementation (
unsigned long num_threads
) :
task_done_signaler(m),
@ -21,7 +21,7 @@ namespace dlib
tasks.resize(num_threads);
for (unsigned long i = 0; i < num_threads; ++i)
{
register_thread(*this, &thread_pool::thread);
register_thread(*this, &thread_pool_implementation::thread);
}
start();
@ -29,10 +29,33 @@ namespace dlib
// ----------------------------------------------------------------------------------------
thread_pool::
~thread_pool()
void thread_pool_implementation::
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;
task_ready_signaler.broadcast();
}
@ -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 (
) const
{
@ -52,7 +83,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
void thread_pool::
void thread_pool_implementation::
wait_for_task (
uint64 task_id
) const
@ -68,7 +99,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
void thread_pool::
void thread_pool_implementation::
wait_for_all_tasks (
) const
{
@ -97,7 +128,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
bool thread_pool::
bool thread_pool_implementation::
is_worker_thread (
const thread_id_type id
) const
@ -118,7 +149,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
void thread_pool::
void thread_pool_implementation::
thread (
)
{
@ -175,7 +206,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
long thread_pool::
long thread_pool_implementation::
find_empty_task_slot (
) const
{
@ -190,7 +221,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
long thread_pool::
long thread_pool_implementation::
find_ready_task (
) const
{
@ -205,7 +236,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
uint64 thread_pool::
uint64 thread_pool_implementation::
make_next_task_id (
long idx
)
@ -217,7 +248,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
unsigned long thread_pool::
unsigned long thread_pool_implementation::
task_id_to_index (
uint64 id
) const
@ -227,7 +258,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
uint64 thread_pool::
uint64 thread_pool_implementation::
add_task_internal (
const bfp_type& bfp
)
@ -270,7 +301,7 @@ namespace dlib
// ----------------------------------------------------------------------------------------
bool thread_pool::
bool thread_pool_implementation::
is_task_thread (
) const
{

File diff suppressed because it is too large Load Diff

View File

@ -76,11 +76,6 @@ namespace dlib
~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
- if (item.is_ready() == false) then
- the call to this function blocks until the thread processing the task related
@ -223,6 +218,12 @@ namespace dlib
mode any thread that calls add_task() is considered to be
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
Note that if an exception is thrown inside a task thread and
is not caught then the normal rule for uncaught exceptions in
@ -248,7 +249,7 @@ namespace dlib
);
/*!
ensures
- all resources allocated by *this have been freed.
- blocks until all tasks in the pool have finished.
!*/
bool is_task_thread (