Evolve existing multi-threaded code to use C++ 14

Intended Audience

The reader is presumed to know C++ and has addressed multiple threading issues in C++. Hence I presume, you know what are mutex, condition_variable, the need for atomicity while doing a read-modify-write operation etc. Let me describe some C++ 14 features pertaining to writing portable multi-threaded code.

Introduction

The good news is C++14 is thread aware. However re-architecting existing code to use C++ 14 may not viable. But how can we evolve? Let us consider some simple problems first.

Singleton

Consider the following code:

MyClass& getObject()
{
	static MyClass obj;
	return obj;
}

C++98 guarantees that in the single threaded case the constructor for obj will be only called once when the getObject() is first called. For multi-threaded applications this was usually implemented using the double checked locking pattern. In C++14 the above code is thread safe [5]! There is no need for the double checked locking pattern. C++ offers another way to ensure that a function is called only once as shown below[1]

#include <mutex>
std::once_flag flag;
void do_once()
{
    std::call_once(flag, 
                    [](){ 
                      std::cout << "Called once" << std::endl;
                     });
}

No matter how many threads call do_once() “Called once” will printed on the console only once. Note that ‘flag’ will be global or static in most cases.

Synchronization Primitives

Consider a typical producer consumer problem [Djik]. In C++ 14 we could implement it as follows

condition_variable cv;
mutex mut;
queue<Task> Queue;
void producer()
{
	for (;;)
	{
		Task task = NewTask();
		{//critical section
		lock_guard<mutex> lock{ mut }; 
		Queue.push(task);
		}// exit critical section
		cv.notify();
	}
}
void consumer()
{
	for (;;)
	{
		Task task;
		{
                        lock_guard<mutex> lock{ mut }; 
			while (queue.empty()) cv.wait(mut);
			task = queue.first();
		}
		DoWork(myTask);
	}
}

This is a well known solution (See [2], [3]). The condition variable [Hoare] waits for an event, which in this case is queue-not-empty event. Note that there is no Wait-For-All or Wait-For-Any function in the C++ 14 [4]. Wait-For-All blocks until all the events in a collection is triggered and Wait-For-Any waits until at least one event in a collection is triggered. One of the most common reasons for wanting Wait-For-Any is to signal a stop condition. This can be done by setting a global flag so that indicates end of computation. Or, a sentinel task can be used to let consumers know when to stop.

References

  1. E.W. Dijkstra “Information Streams Sharing a Finite Buffer,” Information Processing Letters 1: 179180, 1972, http://www.cs.utexas.edu/users/EWD/ewd03xx/EWD329.PDF
  2. C.A.R. Hoare, “Monitors: An Operating System Structuring Concept,” Communications of the ACM, 17:10, pages 549–557, October 1974
  3. J. Duffy “Concurrent Programming on Windows,” Addison Wesley, 2009
  4. B. Milewski “Broken Promises c0x-futures,” http://bartoszmilewski.com/2009/03/03/broken-promises-c0x-futures/
  5. Herb Sutter “Lock-Free Programming (or, Juggling Razor Blades), Part I,” CppCon 2014,
    https://youtu.be/c1gO9aB9nbs?t=28m26s
Advertisements

About The Sunday Programmer

Joe is an experienced C++/C# developer on Windows. Currently looking out for an opening in C/C++ on Windows or Linux.
This entry was posted in C++, Concurrent Programming, Software Engineering. Bookmark the permalink.

One Response to Evolve existing multi-threaded code to use C++ 14

  1. Pingback: Asio: A Brief Introduction for the Sockets Programmer | The Sunday Programmer

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