Writing Multithreaded Applications in C++
deathbytape.com
deathbytape.com
This may be fine for a trivial example of std::thread and std::mutex but you should almost never do this in practice (there are some exceptions in kernel space when waiting for an I/O device).
I have a few useful rules of thumb when doing multi threaded programming which I want to share:
1) Almost every mutex should be coupled with one or (usually) more condition variables
2) A mutex variable named "mutex" is a code smell. Ditto for condition variables named "cond". They usually have an easy-to-describe function such as "queue_lock", "not_full" or "not_empty".
The reasoning is that you don't know how much data will arrive in the next 100ms and if you sleep either a buffer could overrun or something else could block. Therefore you need to flush the buffer either when enough data has accumulated or if a timeout has occured.
In case that phrase confuses others reading that: a Condition Variable is a sync-related construct - like Mutex or Semaphore. It does not mean "a regular variable that you put on an if". A very bad name for the concept in my opinion.
an example of .then() construct is here[2].
an example of .await() construct is here[3].What happens here is the following:
1. The function is suspected at that line.This suspension does not block the thread and hence the GUI remains responsive. 2. A thread is created and the lambda is run in the new thread. 3. When the lambda completes,the function is unblocked and finish up its work.
The above gives easy to read and non blocking synchronous code.
[1] https://github.com/mhogomchungu/tasks
[2] https://github.com/mhogomchungu/zuluCrypt/blob/d0439a4e36521...
[3] https://github.com/mhogomchungu/zuluCrypt/blob/eadd2643291f3...
I've done a fair amount of concurrent programming in C++; I wrote most of the code for a DARPA Grand Challenge off-road autonomous vehicle a decade ago. That was fun. Some of the code is hard real time, and some isn't. Thread priorities matter. (This was on QNX, which is a hard real time OS.) There are some unusual techniques; for example, I had a "logprintf" function which was non-blocking. "logprintf" wrote to a queue being written to disk by another thread, and if the queue was full, "..." went into the log. "logprintf" thus could not delay a real-time task and could be used safely in hard real time sections.
Yes, the lock will prevent concurrent access but will it prevent the compiler from optimizing away the read completely since main() was the last function that wrote to the variable. I've seen nasty optimization bugs like that happen in C with single threading and strict pointer aliasing and they are not easy to track down.
One could interpret his example program like this (unrolled and tweaked a bit).
int data = 0; //ok data is now guaranteed to be equals to 0
thread t(produce, &data); //called thread with a pointer to data so if i want to read data again i must invalidate my registers
{
lock_guard<mutex> lock(theLock);
data = 5; // i know i set data to 5 here
}
this_thread::sleep_for(chrono::milliseconds(500)); // call contains no references to data, sleep is a "pure" call
{
lock_guard<mutex> lock(theLock); // call contains no references to data
if (data == 5) // i set data to 5 myself, and i haven't done anything that could touch data since then so we optimize away this branch
cout << "data is 5";
}
Will the call to lock_guard simply disable all such kind of optimizations? Or are you required to write memory barriers yourself in some way? I guess a simple way to look at it would be that the compiler assumes that thread will keep the pointer to data and that lock_guard has access to that pointer behind the scenes somehow, so that acquiring the mutex "invalidates" your last write, but that would mean acquiring any mutex would invalidate all variables as the mutex doesn't specify which data-sets it is locking. Am i thinking correctly? Where can i find more information regarding this.The C++ standard, of course :) But if you prefer some lighter reading, either http://www.cplusplus.com/reference/mutex/mutex/unlock/ or http://en.cppreference.com/w/cpp/thread/mutex/unlock explain what happens, in slightly different ways. I usually prefer the cppreference version, because it uses terminology from the standard more consistently, but there is no harm in reading multiple explanations about difficult concepts like these :)
I'd repeat the explanation here, but I think you'd best be served by reading one of the two links above.
#pragma omp parallel for
for(...)
The Wikipedia page isn't a bad starting point: http://en.m.wikipedia.org/wiki/OpenMP
While you can argue whether introducing pragmas as control structure is a good idea or not, the performance issues with high load(>80% total cpu) and the caveats(two OpenMP versions in same app, multiple threads running OpenMP paralleled code & etc) are just not worth it.
TBB[0] is much better option(especially with C++11, where you can use lambdas to warp your to-be-paralleled-code and don't have to put it elsewhere), and you get all sort of goodies with it(e.g. thread-safe-containers).
As far as I know, it's just syntactic sugar over a pretty simple thread pool model. What are the performance issues at high load?
https://github.com/flipcoder/kit/blob/master/toys/src/echo.c...
Implementation upon boost::coroutine here: https://github.com/flipcoder/kit/blob/master/include/kit/asy...
This is only a proof of concept, but it works.
The only real use-case for thread I can see right now, is for large game engine that need to process sound, graphics, networking, and inputs, all at the same time. What other type of application does need to make use of threads ?
One easy example of a sane place for threading that would resonate with this crowd is HTTP servers. A thread pool to serve requests and a few asynchronous threads to handle DB operations and message queue interactions. Most frameworks are doing this for you (with real threads in languages that support it like C C++ Go Java and green threads in languages that don't Python Node/JS Ruby).
The use case is, that you don't block the UI while doing heavy or slow work, e.g. generating previews in an image organizer or fetching http requests in a browser.
Instead of std::thread, I'd rather recommend using std::function and a threadpool like this one:
For these kind of algorithms, it is not possible to divide work up into isolated jobs that can be run entirely independently of others, as until we start solving something like a refinement problem, we don't know what parts of the graph we will need.
That rules out OpenCL and CUDA, as they want to take a job and run it to completion without having to worry about what anyone else is doing.
It also makes multi-processes less attractive. If you have isolated processes and just pass messages between them, then you have the same problem. Do you have one process that handles the shared data structure? Well then you've effectively serialised your program. Do you divide up the data structure between processes? I wouldn't know how to do that as operations may span the partitions.
Perhaps you'll use shared memory between the processes? Well then you're effectively writing multi-threaded code and you might as well use threads.
In the end the easiest way to do things that we know of is to use multiple threads, shared memory, synchronisation primitives and optimistic algorithms.
[1] K. Pingali, D. Nguyen, M. Kulkarni, M. Burtscher, M. A. Hassaan, R. Kaleem, T.-H. Lee, A. Lenharth, R. Manevich, M. M. ndez-Lojo, D. Prountzos, and X. Sui, “The Tao of Parallelism in Algorithms,” presented at the Proceedings of the 32nd Conference on Programming Language Design and Implementation (PLDI), 2011.
There seems to be a terrible amount of cargo culting around safe concurrent programming and the reinvention of the wheel just because somebody heard the original wheel was bad (c.f. Processes and shared memory vs. threads), and the hope that CSP and similar schemes will act as a magik bullet.
In the end you need to think carefully about the design of your program, work out what races might occur, and try encapsulate any shared state mutation in as small an area as possible where it can be sensibly reasoned about. Remember that using concurrent data structures will not automatically make your code safe, put in comments saying why any shortcut you take is safe, and do really thorough code review.
Hahaha, good one ... oh, wait. Are you serious?
The real reasons are the same as they were, including separation of GUI and non-GUI processing in desktop apps, dispersal of bulk work (both computational and operational) across several cores, wrapping of blocking calls to make them asynchronous/cancellable, etc.
What is it that changed today that made you think that well-established multi-threading patterns are no longer relevant?
Not patterns, but usage. I thought things like OpenCL would have made multi core CPU less relevant for intensive calculations, since GPUs are so much more powerful when you need to execute tasks at the same time.
And since processors were single threaded for a very long time, I was wondering what were threads being used for before multi core CPUs, and how did it really change things for GUIs. I mean threads were not really useful on single cores, were they ?
So it just seems to me that threads are just being made useful since multi cores CPUs, not really before. And unless you really need to take full advantage of the CPU when you're making a single app, your app is not always the single one being ran, cores can also run other apps not being threads. One simple software might not always need to take advantage of threads, unless it's a big software like a commercial 3d game.
Number crunching is almost always parallelizable. Computing is not always calculation. As long as you can simplify your program as a set of input/output models, OpenCL/CUDA will help a lot. Of course it's not a silver bullet, so often one might have to reorganize the problem to have a better performing solution.
The more you can tweak an algorithm to fit inside a set of stricter constraint, the better it will perform on a GPU.
Of course, if you have a hard problem, it's always better to be able to build hardware which targets a particular problem for optimal performance. Maybe I'd be more interested in multithreading when CPU will have at least 16 or 32 cores. 4 or 8 cores is not a lot.
Every application you run has at least one thread or how did you think the main function is run? You won't be able to run multiple applications without multi-tasking.
>how did it really change things for GUIs.
GUI applications are usually single threaded. This means if you run anything blocking in that thread the entire application will freeze. The GUI thread can still continue if you run your blocking task in a worker thread.
The OS sheduler will take care of your threads even if you have only a single core to make sure everything remains responsive. (yes they were clearly talking about websites for mobile devices /sarcasm)
The only advantage of parallelism compared to concurrency is more performance.
But that doesn't mean you really need to make use of multi threading in your program, since the OS is already doing it.
> The only advantage of parallelism compared to concurrency is more performance.
Only if your program can be parallelized. And even if you do manage to parallelize it, in the best case, you'll only get a 4X or 8X performance increase, which is not a big order of magnitude.
So, if your program settled on a model of one "process" per connection, you could rapidly run into slowdowns for forking/execing, and you could also make the OS really unhappy with the number of processes running around. Instead, using threads, the "process" lives only in application code, and you can have as many or as few as you'd like, and the OS really won't care.
This, plus all of the usual points about shared memory, easier ownership and communication, simpler programming model, etc. etc.
There are use cases for all the options--OS-level processes, heavy threads ala pthreads, green threads ala JVM, and fibers ala custom engine code and Erlang.