
C++11 multithreading tutorial - g3orge
http://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/
======
exDM69
Multithreaded programming in C++11 is pretty convenient. std::thread, together
with std::chrono are very good threading and timing libraries. The only thing
better than that is using native API's like pthreads + posix clocks.

Here's an example: C++11 has timed wait on mutex and condition variables,
using std::chrono time stamps for absolute and relative times. Most threading
wrappers don't provide this but it's available in pthreads (and I guess
Windows API too). Not only does C++11 provide this but it plays along very
nicely with the clocks in chrono and you can use it with different time
sources, like the monotonic system clock.

I've used both when building multithreaded "main loops" for game/simulation
purposes. Using C++11 threads + chrono is a lot nicer to the programmer than
doing the same with posix pthreads in C. The biggest improvement is exception
safety, type safety and rich types for clocks and timestamps come second.

~~~
ajross
It's pedantry, but pthreads isn't "native" anywhere either. It's a
standardized API on top of lower level primitives (in Linux, clone() and
futex() basically).

------
apaprocki
This kind of threaded for-loop processing is precisely what OpenMP is designed
to take care of without having to control threads directly from your code.
Making sure your code is thread-safe is good practice anyway, and running the
for loop in parallel could be as easy as using:

    
    
      #pragma omp for ...
    

Disclaimer: I haven't found that OpenMP is too useful outside of pure
computation, but it is worth mentioning if all you want to do is run loops in
parallel.

Current spec (pdf): <http://openmp.org/mp-documents/OpenMP3.1-CCard.pdf>

------
gaius
Lots of good posts there. Very mixed reviews on Amazon(.co.uk) of the book he
recommends tho'[1] has anyone else got any opinions on it?

[1] [http://solarianprogrammer.com/2011/10/07/great-book-
about-c1...](http://solarianprogrammer.com/2011/10/07/great-book-about-c11-2/)

~~~
jlarocco
Not directly, but the few Wrox books I've read made such a negative impression
on me that I won't buy their books any more.

One of the Amazon one-star reviews says, "For a book of this size, I would
have expected extensive coverage of key C++ concepts. However, I am very
unsatisfied with this book, since the coverage of C++ is superficial at best."

Sounds exactly like a Wrox book.

------
ArchD
I couldn't find a way to control affinity with the C++11 thread feature. That
seems like a good reason to stick with pthread.

------
shin_lao
How to improve this tutorial:

\- Use lambdas

\- Use std::scoped_ptr or std::shared_ptr

\- Use std::vector instead of C Array

\- Use references instead of pointers

That would prevent unnecessary pitfalls.

~~~
exDM69
Agreed. But, see this comment in the source: //It may seem strange to not use
a vector here, however (at the time of this writing) clang++ doesn't let you
use a vector to store a group of threads

AFAIK, it should be possible to put threads (non-copyable but movable) to a
vector in C++11. Of course, then the vector will not be copyable (but it will
be movable). I think I've even done it, but I used GCC, which has had pretty
good C++11 support for quite a while now. (sorry, I'm too lazy to verify)

~~~
shin_lao
I'm not sure it works even if it's moveable because there's no guarantee it
will make copy elision everywhere it's needed.

One way I was thinking about it was std::vector<std::shared_ptr<std::thread>>

Additionally, this sucks:

#define NUM_THREADS 10

In C++03 you can write

static const int num_threads = 10;

Which is much better.

And instead of:

for(int i=0;i<NUM_THREADS;i++){ t[i] = thread(call_from_thread,i); }

Better use std::generate.

I may look like I'm nitpicking but I think it's paramount in a tutorial to
have all details really, really right so that it may trigger other questions
and go in depth about why things are better a way or the other.

~~~
exDM69
>> I'm not sure it works even if it's moveable because there's no guarantee it
will make copy elision everywhere it's needed.

Of course it works, since std::thread is movable but non-copyable,
std::vector<std::thread> will be movable but non-copyable too. So the compiler
type checking will make sure it's not copied anywhere.

This works like a charm (with GCC 4.7-ish from git):

    
    
      #include <thread>
      #include <vector>
      #include <iostream>
      #include <algorithm>
    
      int main()
      {
          std::vector<std::thread> threads;
    
          for(int i = 0 ; i < 10 ; ++i)
              threads.push_back(std::thread([=]() { std::cout << i << std::endl; }));
    
          std::for_each(threads.begin(), threads.end(), [](std::thread& thread) { thread.join(); });
      }
    

>> Better use std::generate.

I used to nitpick about not using std::algorithms when they're available, but
I grew out of it. I figured out that std::algos are very limited (esp. in
c++98), and while you can use them to do stuff, it usually takes a significant
amount of brainpower only to reformulate your problem to be suitable for
std::algorithms. There are so many situations where a good old loop will
produce more readable code faster, so why bother with the standard algorithms
if they're not a perfect fit?

Btw. has std::generate improved at all in C++11? It's one of the most limited
algorithms in c++98.

~~~
shin_lao
>> it usually takes a significant amount of brainpower only to reformulate
your problem to be suitable for std::algorithms

That's true, but the final result generally ends up with less bugs and better
thought out algorithms. It forces you to think "what problem am I currently
trying to solve?"

