Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
dlib
Commits
b6ae2a6d
"...git@developer.sourcefind.cn:renzhc/diffusers_dcu.git" did not exist on "3383f77441339154a681f7cb378e86c32b39bc45"
Commit
b6ae2a6d
authored
Jun 07, 2011
by
Davis King
Browse files
Improved the thread_pool example program.
parent
cf8e3d6f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
111 additions
and
94 deletions
+111
-94
examples/thread_pool_ex.cpp
examples/thread_pool_ex.cpp
+111
-94
No files found.
examples/thread_pool_ex.cpp
View file @
b6ae2a6d
...
...
@@ -13,6 +13,7 @@
#include "dlib/threads.h"
#include "dlib/misc_api.h" // for dlib::sleep
#include "dlib/logger.h"
#include <vector>
using
namespace
dlib
;
...
...
@@ -33,65 +34,81 @@ thread_pool tp(3);
class
test
{
/*
The thread_pool accepts "tasks" from the user and schedules them
for execution in one of its threads when one becomes available. Each
task is just a request to call a member function on a particular object
(or if you use futures you may make tasks that call global functions).
So here we create a class called test with a few member functions which
we will have the thread pool call as tasks.
The thread_pool accepts "tasks" from the user and schedules them for
execution in one of its threads when one becomes available. Each task
is just a request to call a function. So here we create a class called
test with a few member functions which we will have the thread pool call
as tasks.
*/
public:
void
task
_0
()
void
task
()
{
dlog
<<
LINFO
<<
"task
_0
start"
;
dlog
<<
LINFO
<<
"task start"
;
// Here we ask the thread pool to call this->subtask() three different times
// with different arguments. Note that calls to add_task() will return
// immediately if there is an available thread to hand the task off to. However,
// if there isn't a thread ready then add_task blocks until there is such a thread.
// Also note that since task_0() is executed within the thread pool (see main() below)
future
<
int
>
var
;
var
=
1
;
// Here we ask the thread pool to call this->subtask() and this->subtask2().
// Note that calls to add_task() will return immediately if there is an
// available thread to hand the task off to. However, if there isn't a
// thread ready then add_task() blocks until there is such a thread.
// Also note that since task() is executed within the thread pool (see main() below)
// calls to add_task() will execute the requested task within the calling thread
// in cases where the thread pool is full. This means it is safe to have
// tasks running in the thread pool spawn sub tasks which is what we are doing here.
tp
.
add_task
(
*
this
,
&
test
::
subtask
,
1
);
// schedule call to this->subtask(1)
tp
.
add_task
(
*
this
,
&
test
::
subtask
,
2
);
// schedule call to this->subtask(2)
tp
.
add_task
(
*
this
,
&
test
::
subtask
,
3
);
// schedule call to this->subtask(3)
// wait_for_all_tasks() is a function that blocks until all tasks
// submitted to the thread pool by the thread calling wait_for_all_tasks()
// finish. So this call blocks until the 3 tasks above are done.
// in cases where the thread pool is full. This means it is always safe to
// spawn subtasks from within another task, which is what we are doing here.
tp
.
add_task
(
*
this
,
&
test
::
subtask
,
var
);
// schedule call to this->subtask(var)
tp
.
add_task
(
*
this
,
&
test
::
subtask2
);
// schedule call to this->subtask2()
// Since var is a future, this line will wait for the test::subtask task to
// finish and before allowing us to access the contents of var. var will
// return the integer it contains. In this case result will be assigned
// the value of 2 since var was incremented by subtask().
int
result
=
var
;
// print out the result
dlog
<<
LINFO
<<
"var = "
<<
result
;
// Wait for all the tasks we have started to finish. Note that
// wait_for_all_tasks() only waits for tasks which were started
// by the calling thread. So you don't have to worry about other
// unrelated parts of your application interfering. In this case
// it just waits for subtask2() to finish.
tp
.
wait_for_all_tasks
();
dlog
<<
LINFO
<<
"task
_0
end"
;
dlog
<<
LINFO
<<
"task end"
;
}
void
subtask
(
long
a
)
void
subtask
(
int
&
a
)
{
dlib
::
sleep
(
200
);
dlog
<<
LINFO
<<
"subtask end "
<<
a
;
a
=
a
+
1
;
dlog
<<
LINFO
<<
"subtask end "
;
}
void
task
_1
(
long
a
,
long
b
)
void
sub
task
2
(
)
{
dlog
<<
LINFO
<<
"task_1 start: "
<<
a
<<
", "
<<
b
;
dlib
::
sleep
(
700
);
dlog
<<
LINFO
<<
"task_1 end: "
<<
a
<<
", "
<<
b
;
dlib
::
sleep
(
300
);
dlog
<<
LINFO
<<
"subtask2 end "
;
}
};
// ----------------------------------------------------------------------------------------
void
add
(
long
a
,
long
b
,
long
&
result
)
class
add_value
{
dlib
::
sleep
(
400
);
result
=
a
+
b
;
}
public:
add_value
(
int
value
)
:
val
(
value
)
{
}
void
operator
()(
int
&
a
)
{
a
+=
val
;
}
private:
int
val
;
};
// ----------------------------------------------------------------------------------------
...
...
@@ -100,56 +117,58 @@ int main()
// tell the logger to print out everything
dlog
.
set_level
(
LALL
);
test
a
;
dlog
<<
LINFO
<<
"schedule a few tasks"
;
// schedule a call to a.task_1(10,11)
tp
.
add_task
(
a
,
&
test
::
task_1
,
10
,
11
);
//
schedule the thread pool to call a.task_0().
uint64
id
=
tp
.
add_task
(
a
,
&
test
::
task
_0
);
test
mytask
;
// Schedule the thread pool to call mytask.task(). Note that all forms of add_task()
// pass in the task object by reference. This means you must make sure, in this case,
//
that mytask isn't destructed until after the task has finished executing.
tp
.
add_task
(
mytask
,
&
test
::
task
);
// schedule a call to a.task_1(12,13)
tp
.
add_task
(
a
,
&
test
::
task_1
,
12
,
13
);
// You can also pass task objects to a thread pool by value. So in this case we don't
// have to worry about keeping our own instance of the task. Here we construct a temporary
// add_value object and pass it right in and everything works like it should.
future
<
int
>
num
=
3
;
tp
.
add_task_by_value
(
add_value
(
7
),
num
);
// adds 7 to num
int
result
=
num
.
get
();
dlog
<<
LINFO
<<
"result = "
<<
result
;
// prints result = 10
dlog
<<
LINFO
<<
"wait for a.task_0() to finish"
;
// now wait for our a.task_0() task to finish. To do this we use the id
// returned by add_task to reference the task we want to wait for.
tp
.
wait_for_task
(
id
);
dlog
<<
LINFO
<<
"a.task_0() finished, now start another task_1() call"
;
// schedule a call to a.task_1(14,15)
tp
.
add_task
(
a
,
&
test
::
task_1
,
14
,
15
);
dlog
<<
LINFO
<<
"wait for all tasks to finish"
;
// here we wait for all tasks which were requested by the main thread
// to complete.
tp
.
wait_for_all_tasks
();
dlog
<<
LINFO
<<
"all tasks finished"
;
// The thread pool also allows you to use futures to pass arbitrary objects into the tasks.
// For example:
future
<
long
>
n1
,
n2
,
result
;
n1
=
3
;
n2
=
4
;
// add a task that is supposed to go call add(n1, n2, result);
tp
.
add_task
(
add
,
n1
,
n2
,
result
);
// uncomment this line if your compiler supports the new C++0x lambda functions
//#define COMPILER_SUPPORTS_CPP0X_LAMBDA_FUNCTIONS
#ifdef COMPILER_SUPPORTS_CPP0X_LAMBDA_FUNCTIONS
// This line will wait for the task in the thread pool to finish and when it does
// result will return the integer it contains. In this case r will be assigned a value of 7.
long
r
=
result
;
// print out the result
dlog
<<
LINFO
<<
"result = "
<<
r
;
// In the above examples we had to explicitly create task objects which is
// inconvenient. If you have a compiler which supports C++0x lambda functions
// then you can use the following simpler method.
// We can also use futures with member functions like so:
tp
.
add_task
(
a
,
&
test
::
task_1
,
n1
,
n2
);
// make a task which will just log a message
tp
.
add_task_by_value
([](){
dlog
<<
LINFO
<<
"A message from a lambda function running in another thread."
;
});
// and we can still wait for tasks like so:
// Here we make 10 different tasks, each assigns a different value into
// the elements of the vector vect.
std
::
vector
<
int
>
vect
(
10
);
for
(
unsigned
long
i
=
0
;
i
<
vect
.
size
();
++
i
)
{
// Make a lambda function which takes vect by reference and i by value. So what
// will happen is each assignment statement will run in a thread in the thread_pool.
tp
.
add_task_by_value
([
&
vect
,
i
](){
vect
[
i
]
=
i
;
});
}
// Wait for all tasks which were requested by the main thread to complete.
tp
.
wait_for_all_tasks
();
dlog
<<
LINFO
<<
"all tasks using futures finished"
;
for
(
unsigned
long
i
=
0
;
i
<
vect
.
size
();
++
i
)
{
dlog
<<
LINFO
<<
"vect["
<<
i
<<
"]: "
<<
vect
[
i
];
}
#endif
...
...
@@ -157,26 +176,24 @@ int main()
the time the log message occurred and the value in [] is the thread id for the thread
that generated the log message):
0 INFO [0] main: schedule a few tasks
0 INFO [1] main: task_1 start: 10, 11
0 INFO [2] main: task_0 start
200 INFO [2] main: subtask end 2
200 INFO [3] main: subtask end 1
200 INFO [3] main: task_1 start: 12, 13
201 INFO [0] main: wait for a.task_0() to finish
400 INFO [2] main: subtask end 3
400 INFO [2] main: task_0 end
400 INFO [0] main: a.task_0() finished, now start another task_1() call
401 INFO [2] main: task_1 start: 14, 15
401 INFO [0] main: wait for all tasks to finish
700 INFO [1] main: task_1 end: 10, 11
901 INFO [3] main: task_1 end: 12, 13
1101 INFO [2] main: task_1 end: 14, 15
1101 INFO [0] main: all tasks finished
1503 INFO [0] main: result = 7
1503 INFO [3] main: task_1 start: 3, 4
2203 INFO [3] main: task_1 end: 3, 4
2203 INFO [0] main: all tasks using futures finished
1 INFO [0] main: schedule a few tasks
1 INFO [1] main: task start
1 INFO [0] main: result = 10
201 INFO [2] main: subtask end
201 INFO [1] main: var = 2
201 INFO [2] main: A message from a lambda function running in another thread.
301 INFO [3] main: subtask2 end
301 INFO [1] main: task end
301 INFO [0] main: vect[0]: 0
301 INFO [0] main: vect[1]: 1
301 INFO [0] main: vect[2]: 2
301 INFO [0] main: vect[3]: 3
301 INFO [0] main: vect[4]: 4
301 INFO [0] main: vect[5]: 5
301 INFO [0] main: vect[6]: 6
301 INFO [0] main: vect[7]: 7
301 INFO [0] main: vect[8]: 8
301 INFO [0] main: vect[9]: 9
*/
}
...
...
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