Photo source: Prashant Shrestha

Most parts of the C++11 threading API are pretty straightforward.   You look up the specs for the component you want to use, you read through the information, and off you go.  Piece of cake.  Usually.

But sometimes you can’t find what you’re looking for.  How do you set a thread’s priority or affinity?  How can you poll for the readiness of a future?  When should you notify_all instead of doing a notify_one?

Or maybe your code’s behavior is, shall we say?, not quite what you had in mind.  You pass data by reference to an asynchronously running function, but the function doesn’t see changes you make to the data, yet if you replace the reference with a pointer, everything works fine.  You write a function that spawns a thread and returns, but terminate keeps getting called.  You invoke a function asynchronously, but you find that sometimes (yet not always) it seems to be trashing your thread-local data.

Or possibly you’re perplexed when you make seemingly innocuous changes to your code, yet that opens the door to the wizard of weird.  For example, you replace a shared_future with a “normal” future, because you find that only one thread really needs to use the future, but your program starts doing strange things.  You replace a call to async with the “equivalent” code using packaged_task, but the behavior is far from equivalent.  You replace a call to async with the “equivalent” execution of a function on a thread, but your program intermittently crashes. What gives?

In this talk, I explore some of the lesser-known and easily-overlooked aspects of the C++11 threading API.  The goal isn’t to set you up as a master of API trivia, it’s to prepare you for the transition from programming “Hello Threads” to really knowing what’s going on.