Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Thread
Description: Threading functionality via composition.Keywords: ecl threads
Tutorial Level: INTERMEDIATE
Next Tutorial: Threadable Thread Locks Priorities
Contents
The ecl Thread class adds threadable functionality via composition (i.e. via objects) rather than via inheritance. The default mode is raii style, that is, it initialises and automatically starts a thread when constructed and manages the thread cleanly when the thread object goes out of scope.
It does have an alternative delayed mode which will instantiate a thread object and only begin threading work when loading the start() method with a worker function.
Construction
Construction can be done directly through free and member function handles or via function objects. Refer to the documentation on Function Objects and Reference Wrappers in ecl_utilities for more details about creating and using function objects/reference wrappers (note, use a reference wrapper if you want to pass a 'heavy' function object!).
1 using ecl::utilities::generateFunctionObject;
2
3 int f() {}
4 int g(int i) {}
5 class A {
6 void f() {}
7 void g(int i) {}
8 };
9 class FunctionObject {
10 public:
11 typedef void result_type;
12 void operator()() {
13 //
14 }
15 };
16
17 // ...
18
19 A a;
20 FunctionObject function_object;
21
22 Thread thread1(f)); // Thread a nullary global function.
23 Thread thread2(generateFunctionObject(g, 3)); // Thread a bound unary global function.
24 Thread thread3(&A::f, a); // Thread a nullary member function.
25 Thread thread4(generateFunctionObject(&A::g, a, 2)); // Thread a bound unary member function.
26 Thread thread5(function_object); // Thread a nullary function object.
27 Thread thread6(ref(function_object)); // Thread a reference to a nullary function object.
28
Scope
Also, this object is permitted to go out of scope without affecting the thread that it started (it may very well still be running!). When it goes out of scope, it simply detaches it and lets it clean itself up. At this point you only lose control of administration of the thread (joining, checking if it is running, cancelling etc).
1 void g() {
2 for (int i = 0; i < 10; ++i ) {
3 sleep(1);
4 cout << i << endl;
5 }
6 }
7
8 void create_out_of_scope_thread() {
9 Thread thread(g);
10 } // thread will go out of scope here.
11
12 // ...
13
14 create_out_of_scope_thread();
15 // Cannot manage the thread from here, but it will continue running.
16 sleep(10); // Note that we have no way of joining with it.
17
Stack Size
On embedded systems with no swap its important to watch how much stack memory you supply to the thread. This can be manually specified in the thread constructor.
Priority
Thread priorities can be specified at the point where the function is loaded and designated to start (i.e. either when loading the constructor or the start() function).
If you wish to configure the thread's priority dynamically, you'll have to fall back to using the ecl::set_priority() function directly from inside the worker function.
Refer to the tutorial on priorities for more information.
Other
Other member functions include
cancel() : instructs a running thread to abort at the next permitted interruption point (read the man pages for pthreads for more info).
join() : wait for the running thread to finish.
isRunning() : check to see if the thread is still running.
Error handling is done in debug mode (i.e. -DNDEBUG is not set) via exceptions. These will throw and report any information on the resulting posix errors should they occur.