Back to Basics: Concurrency - Arthur O'Dwyer - CppCon 2020

preview_player
Показать описание
---
One of C++11's flagship features was the introduction of std::thread, along with a complete suite of synchronization primitives and useful patterns such as thread-safe static initialization. In this session, we'll motivate C++11's threading model and explain how to use std::thread effectively. We'll compare and contrast the C++11 synchronization primitives (mutex, condition variable, reader-writer lock, and once-flag) as well as the primitives that are new in C++20 (semaphore, latch, and barrier). In particular, we'll show how to make a mutex and a condition variable work together.
When using threads, it's important to avoid shared mutable state. We'll show how to tame that state via the "blue/green deployment" pattern, and briefly discuss how to use std::future and std::async to safely handle threads that produce answers.
Attendees will leave this session with a strong grasp on "multithreading tactics" in C++11 and beyond.

---
Arthur O'Dwyer is the author of "Mastering the C++17 STL" (Packt 2017) and of professional training courses such as "Intro to C++," "Classic STL: Algorithms, Containers, Iterators," and "The STL From Scratch." (Ask me about training your new hires!) Arthur is occasionally active on the C++ Standards Committee and has a blog mostly about C++. He is also the author of "Colossal Cave: The Board Game," an avid club juggler, and the recipient of four

---

*-----*
*-----*
Рекомендации по теме
Комментарии
Автор

I love "Back to Basics" talks. You can learn so much from them.

kamilziemian
Автор

I love the bathroom analogy. Two persons trying to use the toilet without synchronization can lead to very undefined behavior.

stemei
Автор

Not just informative, educative, but also entertaining!
Thanks for the talk. :-)

kajonkeatirattanasinchai
Автор

wonderful talk and gave a very nice overview of all constructs in just 1 hr. Amazing.

aprasath
Автор

Thank you very much Arthur, a very well prepared talk and slides!

strakhov
Автор

The blue/green pattern at the end of the talk sounds a lot like the Read-Copy-Update pattern used in the Linux kernel. RCU does a bit more, by tracking readers and serializing writers with a mutex.

The blue/green pattern is more like a CAS-based optimistic copy/update pattern which won't tell you how many readers are outstanding unless you hold onto the old `blue`. (That could matter if you want to determine when "everybody" sees the new setting.) As used here, the `shared_ptr` avoids the ABA problem we normally have to worry about with CAS based optimistic updates, so that much is nice.

intvnut
Автор

Excellent lecture for noob like myself.
Concurrency 101 Primer done right!

NKernytskyy
Автор

As for why we call it "blocking, " I finally understood the other day: think of it as traffic. There are only so many pipelines in the CPU. If a software thread occupies one of them, like a car occupies a lane of a highway, instead of going away while waiting, so other code on another software thread can use those hardware threads in the mean time, it rather just sits there and blocks all the work piling up behind it. It'd be like you stopping your car in the middle of the freeway to text back your Tinder crush right away, instead of pulling over to the side of the road first. In either case, you're not making forward progress as you wait to finish the texting session, but in the former case you also block everyone else that could have used that lane.

think
Автор

I agree that busy waiting is foolish, but... this would prevent the compiler optimization: volatile std::atomic<bool> ready;

WyMustIGo
Автор

This is an amazing talk, well explained and very useful, Thanks

jjp
Автор

I think one important point could have made it in this introduction: describe what happens when an exception is thrown from within a thread.
Probably most of the time, you don't want the whole process to be shutdown, and be able to handle the exception in the original/main thread, but, that's not what happens by default.
The way we can pass an exception from one thread to the other is nonobvious and so it's interesting to teach.
That's why I think it's important enough to be talked about in the first introduction.

Random minor observations:
24:56 You skipped over the opportunity to talk about the `mutable` keyword. On the screen, the num_tokens_available function is const, but you're modifying the mtx_ member variable, so I think it's not going to compile unless it's declared mutable.
34:36 You mention that spurious wakeups are not a concern for now, but you actually have the perfect example case on the screen: people might be tempted to replace the `while` with an `if`. I think people should be taught to always use the other overload of the `wait` function that takes the condition predicate as the second argument, in the form of a lambda, because it does the while-loop by itself, so there's no risk someone who's not aware of spurious wakeups might misuse the condition variable.

retropaganda
Автор

I am not sure if someone else did comment on this, but I think the 'optimazation' mentioned at 5:30 into talk might be wrong....the initialization should come after sleep(200).

Gunwar-qx
Автор

18:00 does the compiler really have a right to optimize away the checks on the atomic variable, even when it is shared with another thread?

MaceUA
Автор

It's very handy when the data you want to work on is already broken up, e.g multiple files. Just process each file into it's own location in memory then aggregate the multiple data structures back together. Sometimes it makes sense to not write everything to the same data structure (array, vector, etc) for all your threads. Mutex/locks are slow, my suggestion is try to avoid them if possible.

mworld
Автор

58:00 is there a typo in the `while` loop condition, or have I misunderstood something?
If `compare_exchange_strong` returns `true`, the loop will start all over. But `true` result would mean that we have successfully inserted `green` into `g_config`, so we don't need to iterate anymore.
Thus, shouldn't it be `... while (with a negation), so that we would finish the loop as soon as it returns `true` (and continue iterating while it returns `false`)?

MaceUA
Автор

Very grear talk! Thank you very much! Arthur

chaicblack
Автор

Thank you for the great talk, there's a whole bunch of useful things here.
Is there a typo(s) on slide at 41:25? Capturing conn_ is missing in lambda and there's an extra asterisk after return, it's a reference, not a pointer, you don't need to dereference it.

avedissimracing
Автор

Awesome talk!! Learnt a lot. Thank you! 👍

guanwang
Автор

At 16:51, can the compiler really bring the atomic read out the loop? There's a memory barrier, so surely not? Obviously, if it was just a non-atomic bool it could though.

jackw
Автор

"If you have to ask the question you probably shouldn't be doing it yourself." How else are you supposed to learn. Not a great response there...

PeteBrubaker