Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dlib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
钟尚武
dlib
Commits
8a3ff4ff
Commit
8a3ff4ff
authored
Jun 07, 2011
by
Davis King
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added an add_task_by_value() function to the thread_pool.
parent
cf6f55c2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
243 additions
and
16 deletions
+243
-16
thread_pool_extension.cpp
dlib/threads/thread_pool_extension.cpp
+3
-1
thread_pool_extension.h
dlib/threads/thread_pool_extension.h
+146
-3
thread_pool_extension_abstract.h
dlib/threads/thread_pool_extension_abstract.h
+94
-12
No files found.
dlib/threads/thread_pool_extension.cpp
View file @
8a3ff4ff
...
@@ -260,7 +260,8 @@ namespace dlib
...
@@ -260,7 +260,8 @@ namespace dlib
uint64
thread_pool_implementation
::
uint64
thread_pool_implementation
::
add_task_internal
(
add_task_internal
(
const
bfp_type
&
bfp
const
bfp_type
&
bfp
,
shared_ptr
<
function_object_copy
>&
item
)
)
{
{
auto_mutex
M
(
m
);
auto_mutex
M
(
m
);
...
@@ -293,6 +294,7 @@ namespace dlib
...
@@ -293,6 +294,7 @@ namespace dlib
tasks
[
idx
].
thread_id
=
my_thread_id
;
tasks
[
idx
].
thread_id
=
my_thread_id
;
tasks
[
idx
].
task_id
=
make_next_task_id
(
idx
);
tasks
[
idx
].
task_id
=
make_next_task_id
(
idx
);
tasks
[
idx
].
bfp
=
bfp
;
tasks
[
idx
].
bfp
=
bfp
;
tasks
[
idx
].
function_copy
.
swap
(
item
);
task_ready_signaler
.
signal
();
task_ready_signaler
.
signal
();
...
...
dlib/threads/thread_pool_extension.h
View file @
8a3ff4ff
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include "../uintn.h"
#include "../uintn.h"
#include "../array.h"
#include "../array.h"
#include "../smart_pointers_thread_safe.h"
#include "../smart_pointers_thread_safe.h"
#include "../smart_pointers.h"
namespace
dlib
namespace
dlib
{
{
...
@@ -296,9 +297,34 @@ namespace dlib
...
@@ -296,9 +297,34 @@ namespace dlib
return
tasks
[
idx
].
task_id
;
return
tasks
[
idx
].
task_id
;
}
}
struct
function_object_copy
{
virtual
~
function_object_copy
(){}
};
template
<
typename
T
>
struct
function_object_copy_instance
:
function_object_copy
{
function_object_copy_instance
(
const
T
&
item_
)
:
item
(
item_
)
{}
T
item
;
virtual
~
function_object_copy_instance
(){}
};
uint64
add_task_internal
(
uint64
add_task_internal
(
const
bfp_type
&
bfp
const
bfp_type
&
bfp
,
shared_ptr
<
function_object_copy
>&
item
);
);
/*!
ensures
- adds a task to call the given bfp object.
- swaps item into the internal task object which will have a lifetime
at least as long as the running task.
- returns the task id for this new task
!*/
uint64
add_task_internal
(
const
bfp_type
&
bfp
)
{
shared_ptr
<
function_object_copy
>
temp
;
return
add_task_internal
(
bfp
,
temp
);
}
/*!
/*!
ensures
ensures
- adds a task to call the given bfp object.
- adds a task to call the given bfp object.
...
@@ -424,10 +450,12 @@ namespace dlib
...
@@ -424,10 +450,12 @@ namespace dlib
member_function_pointer
<
long
,
long
>::
kernel_1a
mfp2
;
member_function_pointer
<
long
,
long
>::
kernel_1a
mfp2
;
bfp_type
bfp
;
bfp_type
bfp
;
shared_ptr
<
function_object_copy
>
function_copy
;
};
};
array
<
task_state_type
>::
expand_1d
_c
tasks
;
array
<
task_state_type
>::
expand_1d
tasks
;
array
<
thread_id_type
>::
expand_1d
_c
worker_thread_ids
;
array
<
thread_id_type
>::
expand_1d
worker_thread_ids
;
mutex
m
;
mutex
m
;
signaler
task_done_signaler
;
signaler
task_done_signaler
;
...
@@ -528,6 +556,23 @@ namespace dlib
...
@@ -528,6 +556,23 @@ namespace dlib
return
id
;
return
id
;
}
}
template
<
typename
F
>
uint64
add_task_by_value
(
const
F
&
function_object
)
{
thread_pool_implementation
::
function_object_copy_instance
<
F
>*
ptr
=
0
;
ptr
=
new
thread_pool_implementation
::
function_object_copy_instance
<
F
>
(
function_object
);
shared_ptr
<
thread_pool_implementation
::
function_object_copy
>
function_copy
(
ptr
);
bfp_type
temp
;
temp
.
set
(
ptr
->
item
);
uint64
id
=
impl
->
add_task_internal
(
temp
,
function_copy
);
return
id
;
}
template
<
typename
T
>
template
<
typename
T
>
uint64
add_task
(
uint64
add_task
(
const
T
&
obj
,
const
T
&
obj
,
...
@@ -573,6 +618,26 @@ namespace dlib
...
@@ -573,6 +618,26 @@ namespace dlib
return
id
;
return
id
;
}
}
template
<
typename
F
,
typename
A1
>
uint64
add_task_by_value
(
const
F
&
function_object
,
future
<
A1
>&
arg1
)
{
thread_pool_implementation
::
function_object_copy_instance
<
F
>*
ptr
=
0
;
ptr
=
new
thread_pool_implementation
::
function_object_copy_instance
<
F
>
(
function_object
);
shared_ptr
<
thread_pool_implementation
::
function_object_copy
>
function_copy
(
ptr
);
bfp_type
temp
;
temp
.
set
(
ptr
->
item
,
arg1
.
get
());
uint64
id
=
impl
->
add_task_internal
(
temp
,
function_copy
);
// tie the future to this task
arg1
.
task_id
=
id
;
arg1
.
tp
=
impl
;
return
id
;
}
template
<
typename
T
,
typename
T1
,
typename
A1
>
template
<
typename
T
,
typename
T1
,
typename
A1
>
uint64
add_task
(
uint64
add_task
(
T
&
obj
,
T
&
obj
,
...
@@ -647,6 +712,29 @@ namespace dlib
...
@@ -647,6 +712,29 @@ namespace dlib
return
id
;
return
id
;
}
}
template
<
typename
F
,
typename
A1
,
typename
A2
>
uint64
add_task_by_value
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
)
{
thread_pool_implementation
::
function_object_copy_instance
<
F
>*
ptr
=
0
;
ptr
=
new
thread_pool_implementation
::
function_object_copy_instance
<
F
>
(
function_object
);
shared_ptr
<
thread_pool_implementation
::
function_object_copy
>
function_copy
(
ptr
);
bfp_type
temp
;
temp
.
set
(
ptr
->
item
,
arg1
.
get
(),
arg2
.
get
());
uint64
id
=
impl
->
add_task_internal
(
temp
,
function_copy
);
// tie the future to this task
arg1
.
task_id
=
id
;
arg1
.
tp
=
impl
;
arg2
.
task_id
=
id
;
arg2
.
tp
=
impl
;
return
id
;
}
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
>
typename
T2
,
typename
A2
>
uint64
add_task
(
uint64
add_task
(
...
@@ -736,6 +824,32 @@ namespace dlib
...
@@ -736,6 +824,32 @@ namespace dlib
return
id
;
return
id
;
}
}
template
<
typename
F
,
typename
A1
,
typename
A2
,
typename
A3
>
uint64
add_task_by_value
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
,
future
<
A3
>&
arg3
)
{
thread_pool_implementation
::
function_object_copy_instance
<
F
>*
ptr
=
0
;
ptr
=
new
thread_pool_implementation
::
function_object_copy_instance
<
F
>
(
function_object
);
shared_ptr
<
thread_pool_implementation
::
function_object_copy
>
function_copy
(
ptr
);
bfp_type
temp
;
temp
.
set
(
ptr
->
item
,
arg1
.
get
(),
arg2
.
get
(),
arg3
.
get
());
uint64
id
=
impl
->
add_task_internal
(
temp
,
function_copy
);
// tie the future to this task
arg1
.
task_id
=
id
;
arg1
.
tp
=
impl
;
arg2
.
task_id
=
id
;
arg2
.
tp
=
impl
;
arg3
.
task_id
=
id
;
arg3
.
tp
=
impl
;
return
id
;
}
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
,
typename
T2
,
typename
A2
,
typename
T3
,
typename
A3
>
typename
T3
,
typename
A3
>
...
@@ -840,6 +954,35 @@ namespace dlib
...
@@ -840,6 +954,35 @@ namespace dlib
return
id
;
return
id
;
}
}
template
<
typename
F
,
typename
A1
,
typename
A2
,
typename
A3
,
typename
A4
>
uint64
add_task_by_value
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
,
future
<
A3
>&
arg3
,
future
<
A4
>&
arg4
)
{
thread_pool_implementation
::
function_object_copy_instance
<
F
>*
ptr
=
0
;
ptr
=
new
thread_pool_implementation
::
function_object_copy_instance
<
F
>
(
function_object
);
shared_ptr
<
thread_pool_implementation
::
function_object_copy
>
function_copy
(
ptr
);
bfp_type
temp
;
temp
.
set
(
ptr
->
item
,
arg1
.
get
(),
arg2
.
get
(),
arg3
.
get
(),
arg4
.
get
());
uint64
id
=
impl
->
add_task_internal
(
temp
,
function_copy
);
// tie the future to this task
arg1
.
task_id
=
id
;
arg1
.
tp
=
impl
;
arg2
.
task_id
=
id
;
arg2
.
tp
=
impl
;
arg3
.
task_id
=
id
;
arg3
.
tp
=
impl
;
arg4
.
task_id
=
id
;
arg4
.
tp
=
impl
;
return
id
;
}
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
,
typename
T2
,
typename
A2
,
typename
T3
,
typename
A3
,
typename
T3
,
typename
A3
,
...
...
dlib/threads/thread_pool_extension_abstract.h
View file @
8a3ff4ff
...
@@ -77,9 +77,9 @@ namespace dlib
...
@@ -77,9 +77,9 @@ namespace dlib
);
);
/*!
/*!
ensures
ensures
- if (i
tem.i
s_ready() == false) then
- if (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
to th
e item
future has finished.
to th
is
future has finished.
!*/
!*/
bool
is_ready
(
bool
is_ready
(
...
@@ -218,17 +218,16 @@ namespace dlib
...
@@ -218,17 +218,16 @@ 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
This object is also implemented such that no memory allocations occur
by reference. This means you should ensure that your function
after the thread pool has been constructed (the future object also
objects are not destroyed while tasks are still using them.
doesn't perform any memory allocations or contain any system
(e.g. Don't let them go out of scope right after a call to
resources such as mutex objects) so long as the user doesn't call
a
dd_task())
a
ny of the add_task_by_value() routines.
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
threads applies. That is, the application will be terminated
threads applies. That is, the application will be terminated.
and the text of the exception will be printed to standard error.
!*/
!*/
public
:
public
:
...
@@ -271,6 +270,25 @@ namespace dlib
...
@@ -271,6 +270,25 @@ namespace dlib
the maximum number of tasks that this object will process concurrently.
the maximum number of tasks that this object will process concurrently.
!*/
!*/
template
<
typename
F
>
uint64
add_task_by_value
(
const
F
&
function_object
);
/*!
requires
- function_object() is a valid expression
ensures
- makes a copy of function_object, call it FCOPY.
- if (is_task_thread() == true and there aren't any free threads available) then
- calls FCOPY() 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 FCOPY().
- returns a task id that can be used by this->wait_for_task() to wait
for the submitted task to finish.
!*/
template
<
typename
T
>
template
<
typename
T
>
uint64
add_task
(
uint64
add_task
(
T
&
obj
,
T
&
obj
,
...
@@ -279,6 +297,9 @@ namespace dlib
...
@@ -279,6 +297,9 @@ namespace dlib
/*!
/*!
requires
requires
- funct == a valid member function pointer for class T
- funct == a valid member function pointer for class T
- obj will not go out of scope until after the task has completed (i.e.
this function passes obj to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls (obj.*funct)() within the calling thread and returns
- calls (obj.*funct)() within the calling thread and returns
...
@@ -300,6 +321,9 @@ namespace dlib
...
@@ -300,6 +321,9 @@ namespace dlib
/*!
/*!
requires
requires
- funct == a valid member function pointer for class T
- funct == a valid member function pointer for class T
- obj will not go out of scope until after the task has completed (i.e.
this function passes obj to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls (obj.*funct)(arg1) within the calling thread and returns
- calls (obj.*funct)(arg1) within the calling thread and returns
...
@@ -322,6 +346,9 @@ namespace dlib
...
@@ -322,6 +346,9 @@ namespace dlib
/*!
/*!
requires
requires
- funct == a valid member function pointer for class T
- funct == a valid member function pointer for class T
- obj will not go out of scope until after the task has completed (i.e.
this function passes obj to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls (obj.*funct)(arg1,arg2) within the calling thread and returns
- calls (obj.*funct)(arg1,arg2) within the calling thread and returns
...
@@ -365,6 +392,9 @@ namespace dlib
...
@@ -365,6 +392,9 @@ namespace dlib
requires
requires
- function_object(arg1.get()) is a valid expression
- 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)
(i.e. The A1 type stored in the future must be a type that can be passed into the given function object)
- function_object will not go out of scope until after the task has completed (i.e.
this function passes function_object to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls function_object(arg1.get()) within the calling thread and returns
- calls function_object(arg1.get()) within the calling thread and returns
...
@@ -378,6 +408,28 @@ namespace dlib
...
@@ -378,6 +408,28 @@ namespace dlib
for the submitted task to finish.
for the submitted task to finish.
!*/
!*/
template
<
typename
F
,
typename
A1
>
uint64
add_task_by_value
(
const
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
- makes a copy of function_object, call it FCOPY.
- if (is_task_thread() == true and there aren't any free threads available) then
- calls FCOPY(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 FCOPY(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
>
template
<
typename
T
,
typename
T1
,
typename
A1
>
uint64
add_task
(
uint64
add_task
(
T
&
obj
,
T
&
obj
,
...
@@ -389,6 +441,9 @@ namespace dlib
...
@@ -389,6 +441,9 @@ namespace dlib
- funct == a valid member function pointer for class T
- funct == a valid member function pointer for class T
- (obj.*funct)(arg1.get()) must be a valid expression.
- (obj.*funct)(arg1.get()) must be a valid expression.
(i.e. The A1 type stored in the future must be a type that can be passed into the given function)
(i.e. The A1 type stored in the future must be a type that can be passed into the given function)
- obj will not go out of scope until after the task has completed (i.e.
this function passes obj to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls (obj.*funct)(arg1.get()) within the calling thread and returns
- calls (obj.*funct)(arg1.get()) within the calling thread and returns
...
@@ -413,6 +468,9 @@ namespace dlib
...
@@ -413,6 +468,9 @@ namespace dlib
- funct == a valid member function pointer for class T
- funct == a valid member function pointer for class T
- (obj.*funct)(arg1.get()) must be a valid expression.
- (obj.*funct)(arg1.get()) must be a valid expression.
(i.e. The A1 type stored in the future must be a type that can be passed into the given function)
(i.e. The A1 type stored in the future must be a type that can be passed into the given function)
- obj will not go out of scope until after the task has completed (i.e.
this function passes obj to the task by reference. If you want to avoid
this restriction then use add_task_by_value())
ensures
ensures
- if (is_task_thread() == true and there aren't any free threads available) then
- if (is_task_thread() == true and there aren't any free threads available) then
- calls (obj.*funct)(arg1.get()) within the calling thread and returns
- calls (obj.*funct)(arg1.get()) within the calling thread and returns
...
@@ -450,9 +508,9 @@ namespace dlib
...
@@ -450,9 +508,9 @@ namespace dlib
!*/
!*/
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// The remainder of this class just contains overloads for add_task()
that take up
// The remainder of this class just contains overloads for add_task()
and add_task_by_value()
// to 4 futures (as well as 0 futures). Their behavior is identical to the above
// t
hat take up t
o 4 futures (as well as 0 futures). Their behavior is identical to the above
// add_task() functions.
// add_task()
and add_task_by_value()
functions.
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
template
<
typename
F
,
typename
A1
,
typename
A2
>
template
<
typename
F
,
typename
A1
,
typename
A2
>
...
@@ -462,6 +520,13 @@ namespace dlib
...
@@ -462,6 +520,13 @@ namespace dlib
future
<
A2
>&
arg2
future
<
A2
>&
arg2
);
);
template
<
typename
F
,
typename
A1
,
typename
A2
>
uint64
add_task_by_value
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
);
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
>
typename
T2
,
typename
A2
>
uint64
add_task
(
uint64
add_task
(
...
@@ -498,6 +563,14 @@ namespace dlib
...
@@ -498,6 +563,14 @@ namespace dlib
future
<
A3
>&
arg3
future
<
A3
>&
arg3
);
);
template
<
typename
F
,
typename
A1
,
typename
A2
,
typename
A3
>
uint64
add_task
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
,
future
<
A3
>&
arg3
);
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
,
typename
T2
,
typename
A2
,
typename
T3
,
typename
A3
>
typename
T3
,
typename
A3
>
...
@@ -541,6 +614,15 @@ namespace dlib
...
@@ -541,6 +614,15 @@ namespace dlib
future
<
A4
>&
arg4
future
<
A4
>&
arg4
);
);
template
<
typename
F
,
typename
A1
,
typename
A2
,
typename
A3
,
typename
A4
>
uint64
add_task
(
const
F
&
function_object
,
future
<
A1
>&
arg1
,
future
<
A2
>&
arg2
,
future
<
A3
>&
arg3
,
future
<
A4
>&
arg4
);
template
<
typename
T
,
typename
T1
,
typename
A1
,
template
<
typename
T
,
typename
T1
,
typename
A1
,
typename
T2
,
typename
A2
,
typename
T2
,
typename
A2
,
typename
T3
,
typename
A3
,
typename
T3
,
typename
A3
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment