Multithreading in C++0x

One new feature in C++0x standard is multi-threading support. Previously one need to use different API’s for each platform, which cause headache in porting. Now now C++0x compiler has made mandatory to implement threads for each platform. Let us go through the std::thread class .

Creating a new thread
You just need to construct an object/instance of std::thread and pass a thread start function to it. Thread will finish when the thread start function returns.

void thread_fn() {
}
std::thread my_thr(thread_fn);

There is no restriction that one need to use only normal function, as a thread start function. You also can pass object of the class which overload operator()

class thread_fn {
public:
    void operator() {
    };
};
thread_fn thr_fn_obj;
std::thread my_thr(thr_fn_obj);

Note that this way you are sending copy of the object thread_fn class. If you want to avoid the same and need to use the same object even after thread is finsihed, use std::ref, just wrap the object of your class using std::ref as follows

thread_fn thr_fn_obj;
std::thread my_thr(std::ref(thr_fn_obj));

Argument passing to thread function
In new standard you can pass any number of argument to thread function. C++0x uses variadic template facility to allow variable number of argument in typesafe manner.

void thread_fn(int x, int y) {
}
int a = 5;
int b = 6;
std::thread my_thr(thread_fn,a, b);

Waiting for thread to finish
Going with the POSIX standard, C++0x has provided join API to do the same.

void thread_fn() {
}
std::thread my_thr(thread_fn);
my_thr.join();

Protecting data
With great power of multithreading, it comes the responsibility of the sharing the data. C++0x has provided following basic facility for protecting shared data.

  • non-recursive mutex std::mutex
  • recursive mutes std::recursive_mutex
  • non-recursive with facility to apply timeout for locking std::timed_mutex
  • recursive mutes with timeout for locking std::recursive_timed_mutex

All of those options provides you ownership of the one thread, if you try to lock non-recursive mutex more than once, before unlocking previous ownership, you get undefined behavior. recursive mutex just increment the lock count, for each call and one need to make sure that same number of unlock is being called.
All those classes have lock and unlock member function, it is best to use std::unique_lock and std::lock_guard template, as they are locking in construction. no need to explain the advantage of this approach.
std::unique_lock is very basic and can be used in following form

std::mutex mlock;
my_class data;
void foo() {
    std::lock_guard<std::mutex> lck(mlock);
    perform_operation(data);
} // mutex unlocked here

std::unique_lock provided great list of facility and allows following

  • deferred locking
  • trying to a lock
  • try to lock with a timeout
  • unlocking lock before object is destroyed.
std::timed_mutex m;
my_class data;
void foo() {
    std::unique_lock<std::timed_mutex>
    lk(m,std::chrono::milliseconds(3)); // wait up to 3ms
    if(lk) // if we got the lock, access the data
       process(data);
} // mutex unlocked here

How to avoid deadlock
No need to explain what is dealock and repeating the deadly dreams on solving where is deadlock. C++0x thread library alleviates this problem. In case you need to take multiple locks together, it provides generic std::lock function which can lock all the locks at once.

struct shared_data {
   std::mutex m_lck;
   int a;
   std::string b;
};
void lock_me(shared_data& a, shared_data& b) {
    std::unique_lock<std::mutex> lock_a(a.m_lck,std::defer_lock);
    std::unique_lock<std::mutex> lock_b(b.m_lck,std::defer_lock);
    std::lock(lock_a,lock_b);
    // do something with the internals of a and b
}

Now even if the lock_me is called with lock_me(b,a ), no deadlock will happen.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s