Multithreading in C++0x part 3: Starting Threads with Member Functions and Reference Arguments
Thursday, 26 February 2009
This is the third of a series of blog posts introducing the new C++0x thread library. The first two parts covered Starting Threads in C++0x with simple functions, and starting threads with function objects and additional arguments.
If you've read the previous parts of the series then you've seen how to start threads with functions and function objects, with and without additional arguments. However, the function objects and arguments are always copied into the thread's internal storage. What if you wish to run a member function other than the function call operator, or pass a reference to an existing object?
The C++0x library can handle both these cases: the use of member
functions with std::thread
requires an additional argument for the object on which to invoke the
member function, and references are handled with
std::ref
. Let's take a look at some examples.
Invoking a member function on a new thread
Starting a new thread which runs a member function of an existing
object: you just pass a pointer to the member function and a value to
use as the this
pointer for the object in to the std::thread
constructor.
#include <thread> #include <iostream> class SayHello { public: void greeting() const { std::cout<<"hello"<<std::endl; } }; int main() { SayHello x; std::thread t(&SayHello::greeting,&x); t.join(); }
You can of course pass additional arguments to the member function too:
#include <thread> #include <iostream> class SayHello { public: void greeting(std::string const& message) const { std::cout<<message<<std::endl; } }; int main() { SayHello x; std::thread t(&SayHello::greeting,&x,"goodbye"); t.join(); }
Now, the preceding examples both a plain pointer to a local object
for the this
argument; if you're going to do that, you
need to ensure that the object outlives the thread, otherwise there
will be trouble. An alternative is to use a heap-allocated object and
a reference-counted pointer such as
std::shared_ptr<SayHello>
to ensure that the object
stays around as long as the thread does:
#include <> int main() { std::shared_ptr<SayHello> p(new SayHello); std::thread t(&SayHello::greeting,p,"goodbye"); t.join(); }
So far, everything we've looked at has involved copying the
arguments and thread functions into the internal storage of a thread
even if those arguments are pointers, as in the this
pointers for the member functions. What if you want to pass in a
reference to an existing object, and a pointer just won't do?
That is the task of std::ref
.
Passing function objects and arguments to a thread by reference
Suppose you have an object that implements the function call
operator, and you wish to invoke it on a new thread. The thing is you
want to invoke the function call operator on this particular
object rather than copying it. You could use the member function
support to call operator()
explicitly, but that seems a
bit of a mess given that it is callable already. This is the
first instance in which std::ref
can help — if
x
is a callable object, then std::ref(x)
is
too, so we can pass std::ref(x)
as our function when we
start the thread, as below:
#include <thread> #include <iostream> #include <functional> // for std::ref class PrintThis { public: void operator()() const { std::cout<<"this="<<this<<std::endl; } }; int main() { PrintThis x; x(); std::thread t(std::ref(x)); t.join(); std::thread t2(x); t2.join(); }
In this case, the function call operator just prints the address of
the object. The exact form and values of the output will vary, but the
principle is the same: this little program should output three
lines. The first two should be the same, whilst the third is
different, as it invokes the function call operator on a copy
of x
. For one run on my system it printed the following:
this=0x7fffb08bf7ef this=0x7fffb08bf7ef this=0x42674098
Of course, std::ref
can be used for other arguments
too — the following code will print "x=43":
#include <thread> #include <iostream> #include <functional> void increment(int& i) { ++i; } int main() { int x=42; std::thread t(increment,std::ref(x)); t.join(); std::cout<<"x="<<x<<std::endl; }
When passing in references like this (or pointers for that matter),
you need to be careful not only that the referenced object outlives
the thread, but also that appropriate synchronization is used. In this
case it is fine, because we only access x
before we start
the thread and after it is done, but concurrent access would need
protection with a mutex.
Next time
That wraps up all the variations on starting threads; next time we'll look at using mutexes to protect data from concurrent modification.
Subscribe to the RSS feed or email newsletter for this blog to be sure you don't miss the rest of the series.
Try it out
If you're using Microsoft Visual Studio 2008 or g++ 4.3 or 4.4 on
Ubuntu Linux you can try out the examples from this series using our
just::thread
implementation of the new C++0x thread library. Get your copy
today.
Multithreading in C++0x Series
Here are the posts in this series so far:
- Multithreading in C++0x Part 1: Starting Threads
- Multithreading in C++0x Part 2: Starting Threads with Function Objects and Arguments
- Multithreading in C++0x Part 3: Starting Threads with Member Functions and Reference Arguments
- Multithreading in C++0x Part 4: Protecting Shared Data
- Multithreading
in C++0x Part 5: Flexible locking
with
std::unique_lock<>
- Multithreading in C++0x part 6: Lazy initialization and double-checked locking with atomics
- Multithreading in C++0x part 7: Locking multiple mutexes without deadlock
- Multithreading in C++0x part 8: Futures, Promises and Asynchronous Function Calls
Posted by Anthony Williams
[/ threading /] permanent link
Tags: concurrency, multithreading, C++0x, thread
Stumble It! | Submit to Reddit | Submit to DZone
If you liked this post, why not subscribe to the RSS feed or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Design and Content Copyright © 2005-2024 Just Software Solutions Ltd. All rights reserved. | Privacy Policy
6 Comments
std::vector<> has no member named "get"
The C++ STL class vector has no member function named get(). You probably meant to use at(). <a href="http://types-of-technology.blogspot.com/">Technology Information</a>Nice work Anthony, keep it up.
Hi all,
I have a question, how would I do if I want to write the class SayHello in a separate .cc and .h file (having the main function in a separate file) and still do the same as in this example, that is to create an instance of the class and send it by reference to the run method of the thread?
I appreciate any help, ideas
In my version of the just::thread C++ Thread Library (v1.0) at least the ref() function, defined by including function, appears to be in the tr1 namespace, so in the examples, calls like:
std::thread t(increment,std::ref(x));
need to be modified thus:
std::thread t(increment,std::tr1::ref(x));
Other than that, it works fine. :-)
This is the third of a series of blog posts introducing the new C++0x thread library. The first two parts covered Starting Threads in C++0x with simple functions, and starting threads with function objects and additional arguments.
^ Links with typos.
Excellent Anthony! Thank you!!!