Commit bbf90ce0 authored by Davis King's avatar Davis King

Added the ability to use function objects as tasks and also the ability to

set the number of threads in a thread pool to 0.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402680
parent 381e450b
......@@ -18,13 +18,6 @@ namespace dlib
task_ready_signaler(m),
we_are_destructing(false)
{
// make sure requires clause is not broken
DLIB_ASSERT(num_threads > 0,
"\tthread_pool::thread_pool()"
<< "\n\tthe number of threads in a thread_pool can't be zero"
<< "\n\tthis: " << this
);
tasks.expand(num_threads);
for (unsigned long i = 0; i < num_threads; ++i)
{
......@@ -64,9 +57,12 @@ namespace dlib
) const
{
auto_mutex M(m);
const unsigned long idx = task_id_to_index(task_id);
while (tasks[idx].task_id == task_id)
task_done_signaler.wait();
if (num_threads_in_pool() != 0)
{
const unsigned long idx = task_id_to_index(task_id);
while (tasks[idx].task_id == task_id)
task_done_signaler.wait();
}
}
// ----------------------------------------------------------------------------------------
......@@ -110,7 +106,13 @@ namespace dlib
if (worker_thread_ids[i] == id)
return true;
}
return false;
// if there aren't any threads in the pool then we consider all threads
// to be worker threads
if (num_threads_in_pool() == 0)
return true;
else
return false;
}
// ----------------------------------------------------------------------------------------
......
......@@ -288,6 +288,25 @@ namespace dlib
// --------------------
template <typename F, typename A1>
uint64 add_task (
F& function_object,
future<A1>& arg1
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
bfp_type temp;
temp.set(function_object,arg1.get());
uint64 id = add_task(temp);
// tie the future to this task
arg1.task_id = id;
arg1.tp = this;
return id;
}
template <typename T, typename T1, typename A1>
uint64 add_task (
T& obj,
......@@ -340,6 +359,28 @@ namespace dlib
// --------------------
template <typename F, typename A1, typename A2>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
bfp_type temp;
temp.set(function_object, arg1.get(), arg2.get());
uint64 id = add_task(temp);
// tie the future to this task
arg1.task_id = id;
arg1.tp = this;
arg2.task_id = id;
arg2.tp = this;
return id;
}
template <typename T, typename T1, typename A1,
typename T2, typename A2>
uint64 add_task (
......@@ -404,6 +445,31 @@ namespace dlib
// --------------------
template <typename F, typename A1, typename A2, typename A3>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2,
future<A3>& arg3
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
bfp_type temp;
temp.set(function_object, arg1.get(), arg2.get(), arg3.get());
uint64 id = add_task(temp);
// tie the future to this task
arg1.task_id = id;
arg1.tp = this;
arg2.task_id = id;
arg2.tp = this;
arg3.task_id = id;
arg3.tp = this;
return id;
}
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
......@@ -480,6 +546,34 @@ namespace dlib
// --------------------
template <typename F, typename A1, typename A2, typename A3, typename A4>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2,
future<A3>& arg3,
future<A4>& arg4
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
bfp_type temp;
temp.set(function_object, arg1.get(), arg2.get(), arg3.get(), arg4.get());
uint64 id = add_task(temp);
// tie the future to this task
arg1.task_id = id;
arg1.tp = this;
arg2.task_id = id;
arg2.tp = this;
arg3.task_id = id;
arg3.tp = this;
arg4.task_id = id;
arg4.tp = this;
return id;
}
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
......@@ -586,7 +680,7 @@ namespace dlib
requires
- m is locked
ensures
- if (thread with given id is one of the thread pool's worker threads) then
- if (thread with given id is one of the thread pool's worker threads or num_threads_in_pool() == 0) then
- returns true
- else
- returns false
......@@ -641,6 +735,7 @@ namespace dlib
/*!
requires
- m is locked
- num_threads_in_pool() != 0
ensures
- returns the index in tasks corresponding to the given id
!*/
......
......@@ -201,6 +201,13 @@ namespace dlib
This object represents a fixed size group of threads which you can
submit tasks to and then wait for those tasks to be completed.
Note that setting the number of threads to 0 is a valid way to
use this object. It causes it to not contain any threads
at all. When tasks are submitted to the object in this mode
the tasks are processed within the calling thread. So in this
mode any thread that calls add_task() is considered to be
a thread_pool thread capable of executing tasks.
EXCEPTIONS
Note that if an exception is thrown inside a task thread and
is not caught then the normal rule for uncaught exceptions in
......@@ -213,8 +220,6 @@ namespace dlib
unsigned long num_threads
);
/*!
requires
- num_threads > 0
ensures
- #num_threads_in_pool() == num_threads
throws
......@@ -327,6 +332,29 @@ namespace dlib
// --------------------
template <typename F, typename A1>
uint64 add_task (
F& function_object,
future<A1>& arg1
);
/*!
requires
- function_object(arg1.get()) is a valid expression
(i.e. The A1 type stored in the future must be a type that can be passed into the given function object)
ensures
- if (the thread calling this function is actually one of the threads in the
thread pool and there aren't any free threads available) then
- calls function_object(arg1.get()) within the calling thread and returns
when it finishes
- else
- the call to this function blocks until there is a free thread in the pool
to process this new task. Once a free thread is available the task
is handed off to that thread which then calls function_object(arg1.get()).
- #arg1.is_ready() == false
- returns a task id that can be used by this->wait_for_task() to wait
for the submitted task to finish.
!*/
template <typename T, typename T1, typename A1>
uint64 add_task (
T& obj,
......@@ -406,6 +434,13 @@ namespace dlib
// to 4 futures. Their behavior is identical to the above add_task() functions.
// --------------------------------------------------------------------------------
template <typename F, typename A1, typename A2>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2
);
template <typename T, typename T1, typename A1,
typename T2, typename A2>
uint64 add_task (
......@@ -434,6 +469,14 @@ namespace dlib
// --------------------
template <typename F, typename A1, typename A2, typename A3>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2,
future<A3>& arg3
);
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
......@@ -468,6 +511,15 @@ namespace dlib
// --------------------
template <typename F, typename A1, typename A2, typename A3, typename A4>
uint64 add_task (
F& function_object,
future<A1>& arg1,
future<A2>& arg2,
future<A3>& arg3,
future<A4>& arg4
);
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
......
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