SlideShare une entreprise Scribd logo
1  sur  45
Télécharger pour lire hors ligne
Rainer Grimm: Multithreading done right?
Multithreading done right?
Rainer Grimm: Multithreading done right?
Overview
• Threads
• Shared Variables
• Thread local data
• Condition Variables
• Promise and
Futures
• Memory Model
Rainer Grimm: Multithreading done right?
Threads
• Needs a work package
and run immediately
• The creator has to care
of this child by
• waiting for his child
• detach from his child
• Accepts the data by copy
or by reference
Rainer Grimm: Multithreading done right?
Problems?
#include <iostream>
#include <thread>
int main(){
thread t( []{cout << this_thread::get_id();} );
}
Rainer Grimm: Multithreading done right?
Solution: join or detach
#include <iostream>
#include <thread>
int main(){
thread t( []{cout << this_thread::get_id();} );
t.join();
// t.detach();
}
Rainer Grimm: Multithreading done right?
Problems?
#include <iostream>
#include <thread>
int main(){
thread t([]{cout << this_thread::get_id();});
thread t2([]{cout << this_thread::get_id();});
t= std::move(t2);
t.join();
t2.join();
}
Rainer Grimm: Multithreading done right?
Solution: join or detach
#include <iostream>
#include <thread>
int main(){
thread t([]{cout << this_thread::get_id();});
thread t2([]{std::cout << this_thread::get_id();});
t.join();
t= std::move(t2);
t.join();
cout << "t2.joinable(): " << t2.joinable();
}
Rainer Grimm: Multithreading done right?
Solution: A. Williams "C++ Concurrency in Action"
class scoped_thread{
std::thread t;
public:
explicit scoped_thread(std::thread t_):t(std::move(t_)){
if ( !t.joinable() ) throw std::logic_error("No thread");
}
~scoped_thread(){
t.join();
}
scoped_thread(scoped_thread&)= delete;
scoped_thread& operator=(scoped_thread const &)= delete;
};
int main(){
scoped_thread t(std::thread([]{std::cout << this_thread::get_id();}));
}
Rainer Grimm: Multithreading done right?
Problems?
struct Sleeper{
Sleeper(int& i_):i{i_}{};
void operator() (int k){
for (unsigned int j= 0; j <= 5; ++j){
this_thread::sleep_for(chrono::milliseconds(100));
i += k;
}
}
private:
int& i;
};
int main(){
int valSleeper= 1000;
cout << "valSleeper = " << valSleeper << endl;
thread t(Sleeper(valSleeper),5);
t.detach();
cout << "valSleeper = " << valSleeper << endl;
}
Rainer Grimm: Multithreading done right?
Effect and Solution
thread t(Sleeper(valSleeper),5);
t.join(); // instead of t.detach()
Rainer Grimm: Multithreading done right?
Shared Variables
• Has to be protected
from shared access by
• Atomic variables
• Mutexe
http://www.robinage.com/
Rainer Grimm: Multithreading done right?
Problems?
struct Worker{
Worker(string n):name(n){};
void operator() (){
for (int i= 1; i <= 3; ++i){
this_thread::sleep_for(chrono::milliseconds(200));
cout << name << ": " << "Work " << i << " done !!!" << endl;
}
}
private:
string name;
};
...
cout << "Boss: Let's start working.nn";
thread herb= thread(Worker("Herb"));
thread andrei= thread(Worker(" Andrei"));
thread scott= thread(Worker(" Scott"));
thread bjarne= thread(Worker(" Bjarne"));
thread andrew= thread(Worker(" Andrew"));
thread david= thread(Worker(" David"));
// join all Worker
cout << "n" << "Boss: Let's go home." << endl;
Rainer Grimm: Multithreading done right?
Effect
Rainer Grimm: Multithreading done right?
Solution: Mutex
mutex coutMutex;
struct Worker{
Worker(string n):name(n){};
void operator() (){
for (int i= 1; i <= 3; ++i){
sleep_for(milliseconds(200));
coutMutex.lock();
cout << name << ": " << "Work " <<
i << " done !!!" << endl;
coutMutex.unlock();
}
}
private:
string name;
};
std::cout is thread-safe.
Rainer Grimm: Multithreading done right?
Still a problem?
void operator() (){
for (int i= 1; i <= 3; ++i){
sleep_for(milliseconds(200));
coutMutex.lock();
cout << name << ": " << "Work "
<< i << " done !!!" << endl;
coutMutex.unlock();
}
}
void operator() (){
for (int i= 1; i <= 3; ++i)
sleep_for(milliseconds(200));
lock_guard<mutex>coutGuard(coutMutex);
cout << name << ": " << "Work " << i <<
" done !!!" << endl;
}
}
Mutex Lock
Rainer Grimm: Multithreading done right?
Problems? and Effect!
struct CriticalData{
mutex mut;
};
void lock(CriticalData& a, CriticalData& b){
lock_guard<mutex>guard1(a.mut);
cout << "get the first mutex" << endl;
this_thread::sleep_for(chrono::milliseconds(1));
lock_guard<mutex>guard2(b.mut);
cout << "get the second mutex" << endl;
// do something with a and b
}
int main(){
CriticalData c1;
CriticalData c2;
thread t1([&]{lock(c1,c2);});
thread t2([&]{lock(c2,c1);});
t1.join();
t2.join();
}
Rainer Grimm: Multithreading done right?
Solution: unique_lock
void deadLock(CriticalData& a, CriticalData& b){
unique_lock<mutex>guard1(a.mut,defer_lock);
cout << "Thread: " << get_id() <<" first mutex"<< endl;
this_thread::sleep_for(chrono::milliseconds(1));
unique_lock<mutex>guard2(b.mut,defer_lock);
cout <<" Thread: " << get_id() <<" second mutex"<< endl;
cout <<" Thread: " << get_id() <<" get both mutex" << endl;
lock(guard1,guard2);
}
Rainer Grimm: Multithreading done right?
Problems? and Effect!
int main(){
std::thread t([]{
std::cout << "Still waiting ..." << std::endl;
std::lock_guard<std::mutex> lockGuard(coutMutex);
std::cout << std::this_thread::get_id() << std::endl;
}
);
{
std::lock_guard<std::mutex> lockGuard(coutMutex);
std::cout << std::this_thread::get_id() << std::endl;
t.join();
}
}
Rainer Grimm: Multithreading done right?
Solution: join early
int main(){
std::thread t([]{
std::cout << "Still waiting ..." << std::endl;
std::lock_guard<std::mutex> lockGuard(coutMutex);
std::cout << std::this_thread::get_id() << std::endl;
}
);
{
t.join();
std::lock_guard<std::mutex> lockGuard(coutMutex);
std::cout << std::this_thread::get_id() << std::endl;
}
}
Rainer Grimm: Multithreading done right?
Solution, but ...
mutex myMutex;
class MySingleton{
public:
static MySingleton& getInstance(){
lock_guard<mutex> myLock(myMutex);
if( !instance ) instance= new MySingleton();
return *instance;
}
private:
MySingleton();
~MySingleton();
MySingleton(const MySingleton&)= delete;
MySingleton& operator=(const MySingleton&)= delete;
static MySingleton* instance;
};
MySingleton::MySingleton()= default;
MySingleton::~MySingleton()= default;
MySingleton* MySingleton::instance= nullptr;
...
MySingleton::getInstance();
Rainer Grimm: Multithreading done right?
Problems? Double-Checked Locking Pattern
class MySingleton{
static mutex myMutex;
public:
static MySingleton& getInstance(){
if ( !instance ){
lock_guard<mutex> myLock(myMutex);
if( !instance ) instance= new MySingleton();
return *instance;
}
}
...
instance= new MySingleton(); is not atomic
Possible execution order 1, 3 and 2
1. Allocate memory for MySingleton
2. Create MySingleton object in the memory
3. Refer instance to MySingleton object
Rainer Grimm: Multithreading done right?
Solution: call_once, Meyers Singleton or Atomics
class MySingleton{
public:
static MySingleton& getInstance(){
call_once(initInstanceFlag,
&MySingleton::initSingleton);
return *instance;
}
private:
...
static once_flag initInstanceFlag;
static void initSingleton(){
instance= new MySingleton;
}
};
...
once_flag MySingleton::initInstanceFlag;
class MySingleton{
public:
static MySingleton& getInstance(){
static MySingleton instance;
return instance;
}
private:
...
call_once and once_flag Meyers Singleton
Atomic variables
Rainer Grimm: Multithreading done right?
Thread Local Data
• Are exclusively owned by a thread
• Each thread has his own copy of the data
• Behave like static data
• will be created at the first usage
• are bound to the lifetime of their thread
Rainer Grimm: Multithreading done right?
Problems?
mutex coutMutex;
thread_local string s("hello from ");
void addThreadLocal(string const& s2){
s+=s2;
lock_guard<mutex> guard(coutMutex);
cout << s << endl;
cout << "&s: " << &s << endl;
cout << endl;
}
int main(){
thread t1(addThreadLocal,"t1");
thread t2(addThreadLocal,"t2");
thread t3(addThreadLocal,"t3");
thread t4(addThreadLocal,"t4");
t1.join(), t2.join(), t3.join(),t4.join();
}
Rainer Grimm: Multithreading done right?
Condition Variables
• Empowers threads to
synchronize via
notifications
• One threads produces a
result, a other thread is
still waiting for
• The producer notifies one
or more consumers
Rainer Grimm: Multithreading done right?
Problems?
mutex mutex_;
condition_variable condVar;
void waitingForWork(){
unique_lock<mutex> lck(mutex_);
condVar.wait(lck);
}
void setDataReady(){
condVar.notify_one();
}
int main(){
thread t1(waitingForWork);
thread t2(setDataReady);
t1.join();
t2.join();
}
bool dataReady= false;
void waitingForWork(){
unique_lock<mutex> lck(mutex_);
condVar.wait(lck,[]{return dataReady;});
}
void setDataReady(){
{
lock_guard<mutex> lck(mutex_);
dataReady=true;
}
condVar.notify_one();
}
Spurious Wakeup
Rainer Grimm: Multithreading done right?
Problems?
mutex mutex_;
condition_variable condVar;
void waitingForWork(){
unique_lock<mutex> lck(mutex_);
condVar.wait(lck,[]{return dataReady;});
}
void setDataReady(){
{
lock_guard<mutex> lck(mutex_);
dataReady=true;
}
condVar.notify_one();
}
...
thread t1(setDataReady);
// short time delay
thread t2(waitingForWork);
t1.join(), t2.join();
}
Lost Wakeup
• The condition_variable class is a
synchronization primitive that can be used
to block a thread, or multiple threads at the
same time, ...
http://en.cppreference.com/w/cpp/thread/condition_variable
Rainer Grimm: Multithreading done right?
Problem: A lot to do.
Rainer Grimm: Multithreading done right?
Solution: Boss
preparedCount.store(0); // atomic
Worker herb(" Herb"), thread herbWork(herb);
...
Worker david(" David"), thread davidWork(david);
cout << "BOSS: PREPARE YOUR WORK.n " << endl;
unique_lock<mutex> preparedUniqueLock( preparedMutex );
worker2BossCondVariable.wait(preparedUniqueLock,[]{ return preparedCount == 6; });
startWork= true; cout << "nBOSS: START YOUR WORK. n" << endl;
doneCount.store(0); // atomic
boss2WorkerCondVariable.notify_all();
unique_lock<mutex> doneUniqueLock( doneMutex );
worker2BossCondVariable.wait(doneUniqueLock,[]{ return doneCount == 6; });
goHome= true; cout << "nBOSS: GO HOME. n" << endl;
boss2WorkerCondVariable.notify_all();
// join all Worker
Rainer Grimm: Multithreading done right?
Solution: Worker
struct Worker{
Worker(string n):name(n){};
void operator() (){
int prepareTime= getRandomTime(500,2000);
this_thread::sleep_for(milliseconds(prepareTime));
preparedCount++;
cout << name << ": " << "Work prepared after " << prepareTime << " milliseconds." << endl;
worker2BossCondVariable.notify_one();
{ // wait for the boss
unique_lock<mutex> startWorkLock( startWorkMutex );
boss2WorkerCondVariable.wait( startWorkLock,[]{ return startWork;});
}
int workTime= getRandomTime(200,400);
this_tread::sleep_for(milliseconds(workTime));
doneCount++;
cout << name << ": " << "Work done after " << workTime << " milliseconds." << endl;
worker2BossCondVariable.notify_one();
{ // wait for the boss
unique_lock<mutex> goHomeLock( goHomeMutex );
boss2WorkerCondVariable.wait( goHomeLock,[]{ return goHome;});
}
}
....
Use Tasks.
Rainer Grimm: Multithreading done right?
Promise and Futures
• Are channels between a
Sender and a Receiver
• The Producer puts a
value in the channel, the
Consumer is waiting for
• The Sender is called
Promise, the Receiver
Future
Rainer Grimm: Multithreading done right?
Promise and Futures: A little bit of background.
• implicit with std::async
• explicit with std::future and std::promise
int a= 2000;
int b= 11;
future<int> sumFuture= async([=]{ return a+b; });
sumFuture.get(); // 2011
void sum(promise<int>&& intProm, int x, int y){
intProm.set_value(x+y);
}
promise<int> sumPromise;
future<int> futRes= sumPromise.get_future();
thread sumThread(&sum, move(sumPromise),a,b);
futRes.get(); // 2011
Rainer Grimm: Multithreading done right?
Problem: A lot to do.
Rainer Grimm: Multithreading done right?
Solution: Boss
promise<void> startWorkProm;
promise<void> goHomeProm;
shared_future<void> startWorkFut= startWorkProm.get_future();
shared_future<void> goHomeFut= goHomeProm.get_future();
promise<void> herbPrepared;
future<void> waitForHerbPrepared= herbPrepared.get_future();
promise<void> herbDone;
future<void> waitForHerbDone= herbDone.get_future();
Worker herb(" Herb");
thread herbWork(herb,move(herbPrepared),startWorkFut,move(herbDone),goHomeFut);
...
cout << "BOSS: PREPARE YOUR WORK.n " << endl;
waitForHerbPrepared.wait(), waitForScottPrepared.wait(), waitFor ...
cout << "nBOSS: START YOUR WORK. n" << endl;
startWorkProm.set_value();
waitForHerbDone.wait(), waitForScottDone.wait(), waitFor ...
cout << "nBOSS: GO HOME. n" << endl;
goHomeProm.set_value();
// join all Worker
Rainer Grimm: Multithreading done right?
Solution: Worker
struct Worker{
Worker(string n):name(n){};
void operator() (promise<void>&& preparedWork, shared_future<void> boss2WorkerStartWork,
promise<void>&& doneWork, shared_future<void>boss2WorkerGoHome ){
int prepareTime= getRandomTime(500,2000);
this_thread::sleep_for(milliseconds(prepareTime));
preparedWork.set_value();
cout << name << ": " << "Work prepared after " << prepareTime << " milliseconds." << endl;
boss2WorkerStartWork.wait();
int workTime= getRandomTime(200,400);
this_thread::sleep_for(milliseconds(workTime));
doneWork.set_value();
cout << name << ": " << "Work done after " << workTime << " milliseconds." << endl;
boss2WorkerGoHome.wait();
}
private:
string name;
};
Rainer Grimm: Multithreading done right?
Memory Model
• The Memory Model
deals with
• atomic operations
• partial ordering of
operations
• visible effect of
operations
Rainer Grimm: Multithreading done right?
Problems?
int x= 0;
int y= 0;
void writing(){
x= 2000;
y= 11;
}
void reading(){
cout << "y: " << y << " ";
cout << "x: " << x << endl;
}
int main(){
thread thread1(writing);
thread thread2(reading);
thread1.join();
thread2.join();
};
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Mutex
int x= 0;
int y= 0;
mutex mut;
void writing(){
lock_guard<mutex> guard(mut);
x= 2000;
y= 11;
}
void reading(){
lock_guard<mutex> guard(mut)
cout << "y: " << y << " ";
cout << "x: " << x << endl;
}
...
thread thread1(writing);
thread thread2(reading);
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Atomic
atomic<int> x= 0;
atomic<int> y= 0;
void writing(){
x.store(2000);
y.store(11);
}
void reading(){
cout << y.load() << " ";
cout << x.load() << endl;
}
...
thread thread1(writing);
thread thread2(reading);
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Atomic with acquire release semantic
atomic<int> x= 0;
atomic<int> y= 0;
void writing(){
x.store(2000,memory_order_relaxed);
y.store(11, memory_order_release);
}
void reading(){
cout << y.load(memory_order_acquire) << " ";
cout << x.load(memory_order_relaxed) << endl;
}
...
thread thread1(writing);
thread thread2(reading);
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Atomic with sychronization of non atomics
int x= 0;
atomic<int> y= 0;
void writing(){
x= 2000;
y.store(11, memory_order_release);
}
void reading(){
cout << y.load(memory_order_acquire) << " ";
cout << x << endl;
}
...
thread thread1(writing);
thread thread2(reading);
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Atomic with relaxed semantik
atomic<int> x= 0;
atomic<int> y= 0;
void writing(){
x.store(2000,memory_order_relaxed);
y.store(11, memory_order_relaxed);
}
void reading(){
cout << y.load(memory_order_relaxed) << " ";
cout << x.load(memory_order_relaxed) << endl;
}
...
thread thread1(writing);
thread thread2(reading);
y x Yes
0 0
11 0
0 2000
11 2000
Rainer Grimm: Multithreading done right?
Solution: Singleton with Atomics
class MySingleton{
static mutex myMutex;
static atomic<MySingleton*> instance;
public:
static MySingleton* getInstance(){
MySingleton* sin= instance.load(); instance.load(memory_order_acquire);
if ( !sin ){
lock_guard<mutex> myLock(myMutex);
if( !sin ){
sin= new MySingleton();
instance.store(sin); instance.store(sin,memory_order_release);
}
}
return sin;
}
...
Sequentially Consistent Acquire-Release
Rainer Grimm: Multithreading done right?
The Solution : CppMem
CppMem
Rainer Grimm: Multithreading done right?
Thank you for your attention
Rainer Grimm
Metrax GmbH
www.primedic.com
Phone +49 (0)741 257-0
Rainer.Grimm@primedic.com

Contenu connexe

Tendances

GPU Programming on CPU - Using C++AMP
GPU Programming on CPU - Using C++AMPGPU Programming on CPU - Using C++AMP
GPU Programming on CPU - Using C++AMP
Miller Lee
 
Building High-Performance Language Implementations With Low Effort
Building High-Performance Language Implementations With Low EffortBuilding High-Performance Language Implementations With Low Effort
Building High-Performance Language Implementations With Low Effort
Stefan Marr
 
Choosing the right parallel compute architecture
Choosing the right parallel compute architecture Choosing the right parallel compute architecture
Choosing the right parallel compute architecture
corehard_by
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/O
Jussi Pohjolainen
 

Tendances (20)

Non-blocking synchronization — what is it and why we (don't?) need it
Non-blocking synchronization — what is it and why we (don't?) need itNon-blocking synchronization — what is it and why we (don't?) need it
Non-blocking synchronization — what is it and why we (don't?) need it
 
分散式系統
分散式系統分散式系統
分散式系統
 
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствамиАнтон Наумович, Система автоматической крэш-аналитики своими средствами
Антон Наумович, Система автоматической крэш-аналитики своими средствами
 
Global Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the SealGlobal Interpreter Lock: Episode I - Break the Seal
Global Interpreter Lock: Episode I - Break the Seal
 
Async await in C++
Async await in C++Async await in C++
Async await in C++
 
модели акторов в с++ миф или реальность
модели акторов в с++ миф или реальностьмодели акторов в с++ миф или реальность
модели акторов в с++ миф или реальность
 
Silicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM MechanicsSilicon Valley JUG: JVM Mechanics
Silicon Valley JUG: JVM Mechanics
 
GPU Programming on CPU - Using C++AMP
GPU Programming on CPU - Using C++AMPGPU Programming on CPU - Using C++AMP
GPU Programming on CPU - Using C++AMP
 
Building High-Performance Language Implementations With Low Effort
Building High-Performance Language Implementations With Low EffortBuilding High-Performance Language Implementations With Low Effort
Building High-Performance Language Implementations With Low Effort
 
Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...
Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...
Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...
 
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
 
Effective java - concurrency
Effective java - concurrencyEffective java - concurrency
Effective java - concurrency
 
Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency Idioms
 
bluespec talk
bluespec talkbluespec talk
bluespec talk
 
Node.js System: The Landing
Node.js System: The LandingNode.js System: The Landing
Node.js System: The Landing
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency Gotchas
 
How Data Flow analysis works in a static code analyzer
How Data Flow analysis works in a static code analyzerHow Data Flow analysis works in a static code analyzer
How Data Flow analysis works in a static code analyzer
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
 
Choosing the right parallel compute architecture
Choosing the right parallel compute architecture Choosing the right parallel compute architecture
Choosing the right parallel compute architecture
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/O
 

En vedette

Multi threading design pattern
Multi threading design patternMulti threading design pattern
Multi threading design pattern
Yan Wang
 

En vedette (20)

Конверсия управляемых языков в неуправляемые
Конверсия управляемых языков в неуправляемыеКонверсия управляемых языков в неуправляемые
Конверсия управляемых языков в неуправляемые
 
Практика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверПрактика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-сервер
 
Конкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнерыКонкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнеры
 
Multithreading 101
Multithreading 101Multithreading 101
Multithreading 101
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
 
What's New in C++ 11/14?
What's New in C++ 11/14?What's New in C++ 11/14?
What's New in C++ 11/14?
 
High quality library from scratch
High quality library from scratchHigh quality library from scratch
High quality library from scratch
 
What's New in C++ 11?
What's New in C++ 11?What's New in C++ 11?
What's New in C++ 11?
 
Beating the (sh** out of the) GIL - Multithreading vs. Multiprocessing
Beating the (sh** out of the) GIL - Multithreading vs. MultiprocessingBeating the (sh** out of the) GIL - Multithreading vs. Multiprocessing
Beating the (sh** out of the) GIL - Multithreading vs. Multiprocessing
 
Debugging and Profiling C++ Template Metaprograms
Debugging and Profiling C++ Template MetaprogramsDebugging and Profiling C++ Template Metaprograms
Debugging and Profiling C++ Template Metaprograms
 
Intro To .Net Threads
Intro To .Net ThreadsIntro To .Net Threads
Intro To .Net Threads
 
Generics C#
Generics C#Generics C#
Generics C#
 
Multi threading design pattern
Multi threading design patternMulti threading design pattern
Multi threading design pattern
 
Address/Thread/Memory Sanitizer
Address/Thread/Memory SanitizerAddress/Thread/Memory Sanitizer
Address/Thread/Memory Sanitizer
 
C# Advanced L04-Threading
C# Advanced L04-ThreadingC# Advanced L04-Threading
C# Advanced L04-Threading
 
Multithreading Design Patterns
Multithreading Design PatternsMultithreading Design Patterns
Multithreading Design Patterns
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
 
Дмитрий Копляров , Потокобезопасные сигналы в C++
Дмитрий Копляров , Потокобезопасные сигналы в C++Дмитрий Копляров , Потокобезопасные сигналы в C++
Дмитрий Копляров , Потокобезопасные сигналы в C++
 
Threading in C#
Threading in C#Threading in C#
Threading in C#
 

Similaire à Multithreading done right

13multithreaded Programming
13multithreaded Programming13multithreaded Programming
13multithreaded Programming
Adil Jafri
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Yandex
 
Multithreaded programming
Multithreaded programmingMultithreaded programming
Multithreaded programming
Sonam Sharma
 
Concurrency in Python
Concurrency in PythonConcurrency in Python
Concurrency in Python
Gavin Roy
 
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Yandex
 

Similaire à Multithreading done right (20)

Multi threading
Multi threadingMulti threading
Multi threading
 
Qt multi threads
Qt multi threadsQt multi threads
Qt multi threads
 
13multithreaded Programming
13multithreaded Programming13multithreaded Programming
13multithreaded Programming
 
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан КольцовRust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
 
Actor Concurrency
Actor ConcurrencyActor Concurrency
Actor Concurrency
 
Rust "Hot or Not" at Sioux
Rust "Hot or Not" at SiouxRust "Hot or Not" at Sioux
Rust "Hot or Not" at Sioux
 
Optimizing Parallel Reduction in CUDA : NOTES
Optimizing Parallel Reduction in CUDA : NOTESOptimizing Parallel Reduction in CUDA : NOTES
Optimizing Parallel Reduction in CUDA : NOTES
 
P threads
P threadsP threads
P threads
 
Tools and Techniques for Understanding Threading Behavior in Android
Tools and Techniques for Understanding Threading Behavior in AndroidTools and Techniques for Understanding Threading Behavior in Android
Tools and Techniques for Understanding Threading Behavior in Android
 
Posix Threads
Posix ThreadsPosix Threads
Posix Threads
 
Multithreaded programming
Multithreaded programmingMultithreaded programming
Multithreaded programming
 
Python multithreading
Python multithreadingPython multithreading
Python multithreading
 
Python multithreading
Python multithreadingPython multithreading
Python multithreading
 
Introduction to Rust language programming
Introduction to Rust language programmingIntroduction to Rust language programming
Introduction to Rust language programming
 
Concurrency in Python
Concurrency in PythonConcurrency in Python
Concurrency in Python
 
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
 
Threading
ThreadingThreading
Threading
 
Introduction to CUDA
Introduction to CUDAIntroduction to CUDA
Introduction to CUDA
 
Python Asíncrono - Async Python
Python Asíncrono - Async PythonPython Asíncrono - Async Python
Python Asíncrono - Async Python
 
Addressing Scenario
Addressing ScenarioAddressing Scenario
Addressing Scenario
 

Plus de Platonov Sergey

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
Platonov Sergey
 

Plus de Platonov Sergey (20)

Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутов
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++
 
C++ exceptions
C++ exceptionsC++ exceptions
C++ exceptions
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим жить
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансы
 
Аскетичная разработка браузера
Аскетичная разработка браузераАскетичная разработка браузера
Аскетичная разработка браузера
 
Concepts lite
Concepts liteConcepts lite
Concepts lite
 

Dernier

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 

Dernier (20)

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 

Multithreading done right

  • 1. Rainer Grimm: Multithreading done right? Multithreading done right?
  • 2. Rainer Grimm: Multithreading done right? Overview • Threads • Shared Variables • Thread local data • Condition Variables • Promise and Futures • Memory Model
  • 3. Rainer Grimm: Multithreading done right? Threads • Needs a work package and run immediately • The creator has to care of this child by • waiting for his child • detach from his child • Accepts the data by copy or by reference
  • 4. Rainer Grimm: Multithreading done right? Problems? #include <iostream> #include <thread> int main(){ thread t( []{cout << this_thread::get_id();} ); }
  • 5. Rainer Grimm: Multithreading done right? Solution: join or detach #include <iostream> #include <thread> int main(){ thread t( []{cout << this_thread::get_id();} ); t.join(); // t.detach(); }
  • 6. Rainer Grimm: Multithreading done right? Problems? #include <iostream> #include <thread> int main(){ thread t([]{cout << this_thread::get_id();}); thread t2([]{cout << this_thread::get_id();}); t= std::move(t2); t.join(); t2.join(); }
  • 7. Rainer Grimm: Multithreading done right? Solution: join or detach #include <iostream> #include <thread> int main(){ thread t([]{cout << this_thread::get_id();}); thread t2([]{std::cout << this_thread::get_id();}); t.join(); t= std::move(t2); t.join(); cout << "t2.joinable(): " << t2.joinable(); }
  • 8. Rainer Grimm: Multithreading done right? Solution: A. Williams "C++ Concurrency in Action" class scoped_thread{ std::thread t; public: explicit scoped_thread(std::thread t_):t(std::move(t_)){ if ( !t.joinable() ) throw std::logic_error("No thread"); } ~scoped_thread(){ t.join(); } scoped_thread(scoped_thread&)= delete; scoped_thread& operator=(scoped_thread const &)= delete; }; int main(){ scoped_thread t(std::thread([]{std::cout << this_thread::get_id();})); }
  • 9. Rainer Grimm: Multithreading done right? Problems? struct Sleeper{ Sleeper(int& i_):i{i_}{}; void operator() (int k){ for (unsigned int j= 0; j <= 5; ++j){ this_thread::sleep_for(chrono::milliseconds(100)); i += k; } } private: int& i; }; int main(){ int valSleeper= 1000; cout << "valSleeper = " << valSleeper << endl; thread t(Sleeper(valSleeper),5); t.detach(); cout << "valSleeper = " << valSleeper << endl; }
  • 10. Rainer Grimm: Multithreading done right? Effect and Solution thread t(Sleeper(valSleeper),5); t.join(); // instead of t.detach()
  • 11. Rainer Grimm: Multithreading done right? Shared Variables • Has to be protected from shared access by • Atomic variables • Mutexe http://www.robinage.com/
  • 12. Rainer Grimm: Multithreading done right? Problems? struct Worker{ Worker(string n):name(n){}; void operator() (){ for (int i= 1; i <= 3; ++i){ this_thread::sleep_for(chrono::milliseconds(200)); cout << name << ": " << "Work " << i << " done !!!" << endl; } } private: string name; }; ... cout << "Boss: Let's start working.nn"; thread herb= thread(Worker("Herb")); thread andrei= thread(Worker(" Andrei")); thread scott= thread(Worker(" Scott")); thread bjarne= thread(Worker(" Bjarne")); thread andrew= thread(Worker(" Andrew")); thread david= thread(Worker(" David")); // join all Worker cout << "n" << "Boss: Let's go home." << endl;
  • 13. Rainer Grimm: Multithreading done right? Effect
  • 14. Rainer Grimm: Multithreading done right? Solution: Mutex mutex coutMutex; struct Worker{ Worker(string n):name(n){}; void operator() (){ for (int i= 1; i <= 3; ++i){ sleep_for(milliseconds(200)); coutMutex.lock(); cout << name << ": " << "Work " << i << " done !!!" << endl; coutMutex.unlock(); } } private: string name; }; std::cout is thread-safe.
  • 15. Rainer Grimm: Multithreading done right? Still a problem? void operator() (){ for (int i= 1; i <= 3; ++i){ sleep_for(milliseconds(200)); coutMutex.lock(); cout << name << ": " << "Work " << i << " done !!!" << endl; coutMutex.unlock(); } } void operator() (){ for (int i= 1; i <= 3; ++i) sleep_for(milliseconds(200)); lock_guard<mutex>coutGuard(coutMutex); cout << name << ": " << "Work " << i << " done !!!" << endl; } } Mutex Lock
  • 16. Rainer Grimm: Multithreading done right? Problems? and Effect! struct CriticalData{ mutex mut; }; void lock(CriticalData& a, CriticalData& b){ lock_guard<mutex>guard1(a.mut); cout << "get the first mutex" << endl; this_thread::sleep_for(chrono::milliseconds(1)); lock_guard<mutex>guard2(b.mut); cout << "get the second mutex" << endl; // do something with a and b } int main(){ CriticalData c1; CriticalData c2; thread t1([&]{lock(c1,c2);}); thread t2([&]{lock(c2,c1);}); t1.join(); t2.join(); }
  • 17. Rainer Grimm: Multithreading done right? Solution: unique_lock void deadLock(CriticalData& a, CriticalData& b){ unique_lock<mutex>guard1(a.mut,defer_lock); cout << "Thread: " << get_id() <<" first mutex"<< endl; this_thread::sleep_for(chrono::milliseconds(1)); unique_lock<mutex>guard2(b.mut,defer_lock); cout <<" Thread: " << get_id() <<" second mutex"<< endl; cout <<" Thread: " << get_id() <<" get both mutex" << endl; lock(guard1,guard2); }
  • 18. Rainer Grimm: Multithreading done right? Problems? and Effect! int main(){ std::thread t([]{ std::cout << "Still waiting ..." << std::endl; std::lock_guard<std::mutex> lockGuard(coutMutex); std::cout << std::this_thread::get_id() << std::endl; } ); { std::lock_guard<std::mutex> lockGuard(coutMutex); std::cout << std::this_thread::get_id() << std::endl; t.join(); } }
  • 19. Rainer Grimm: Multithreading done right? Solution: join early int main(){ std::thread t([]{ std::cout << "Still waiting ..." << std::endl; std::lock_guard<std::mutex> lockGuard(coutMutex); std::cout << std::this_thread::get_id() << std::endl; } ); { t.join(); std::lock_guard<std::mutex> lockGuard(coutMutex); std::cout << std::this_thread::get_id() << std::endl; } }
  • 20. Rainer Grimm: Multithreading done right? Solution, but ... mutex myMutex; class MySingleton{ public: static MySingleton& getInstance(){ lock_guard<mutex> myLock(myMutex); if( !instance ) instance= new MySingleton(); return *instance; } private: MySingleton(); ~MySingleton(); MySingleton(const MySingleton&)= delete; MySingleton& operator=(const MySingleton&)= delete; static MySingleton* instance; }; MySingleton::MySingleton()= default; MySingleton::~MySingleton()= default; MySingleton* MySingleton::instance= nullptr; ... MySingleton::getInstance();
  • 21. Rainer Grimm: Multithreading done right? Problems? Double-Checked Locking Pattern class MySingleton{ static mutex myMutex; public: static MySingleton& getInstance(){ if ( !instance ){ lock_guard<mutex> myLock(myMutex); if( !instance ) instance= new MySingleton(); return *instance; } } ... instance= new MySingleton(); is not atomic Possible execution order 1, 3 and 2 1. Allocate memory for MySingleton 2. Create MySingleton object in the memory 3. Refer instance to MySingleton object
  • 22. Rainer Grimm: Multithreading done right? Solution: call_once, Meyers Singleton or Atomics class MySingleton{ public: static MySingleton& getInstance(){ call_once(initInstanceFlag, &MySingleton::initSingleton); return *instance; } private: ... static once_flag initInstanceFlag; static void initSingleton(){ instance= new MySingleton; } }; ... once_flag MySingleton::initInstanceFlag; class MySingleton{ public: static MySingleton& getInstance(){ static MySingleton instance; return instance; } private: ... call_once and once_flag Meyers Singleton Atomic variables
  • 23. Rainer Grimm: Multithreading done right? Thread Local Data • Are exclusively owned by a thread • Each thread has his own copy of the data • Behave like static data • will be created at the first usage • are bound to the lifetime of their thread
  • 24. Rainer Grimm: Multithreading done right? Problems? mutex coutMutex; thread_local string s("hello from "); void addThreadLocal(string const& s2){ s+=s2; lock_guard<mutex> guard(coutMutex); cout << s << endl; cout << "&s: " << &s << endl; cout << endl; } int main(){ thread t1(addThreadLocal,"t1"); thread t2(addThreadLocal,"t2"); thread t3(addThreadLocal,"t3"); thread t4(addThreadLocal,"t4"); t1.join(), t2.join(), t3.join(),t4.join(); }
  • 25. Rainer Grimm: Multithreading done right? Condition Variables • Empowers threads to synchronize via notifications • One threads produces a result, a other thread is still waiting for • The producer notifies one or more consumers
  • 26. Rainer Grimm: Multithreading done right? Problems? mutex mutex_; condition_variable condVar; void waitingForWork(){ unique_lock<mutex> lck(mutex_); condVar.wait(lck); } void setDataReady(){ condVar.notify_one(); } int main(){ thread t1(waitingForWork); thread t2(setDataReady); t1.join(); t2.join(); } bool dataReady= false; void waitingForWork(){ unique_lock<mutex> lck(mutex_); condVar.wait(lck,[]{return dataReady;}); } void setDataReady(){ { lock_guard<mutex> lck(mutex_); dataReady=true; } condVar.notify_one(); } Spurious Wakeup
  • 27. Rainer Grimm: Multithreading done right? Problems? mutex mutex_; condition_variable condVar; void waitingForWork(){ unique_lock<mutex> lck(mutex_); condVar.wait(lck,[]{return dataReady;}); } void setDataReady(){ { lock_guard<mutex> lck(mutex_); dataReady=true; } condVar.notify_one(); } ... thread t1(setDataReady); // short time delay thread t2(waitingForWork); t1.join(), t2.join(); } Lost Wakeup • The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, ... http://en.cppreference.com/w/cpp/thread/condition_variable
  • 28. Rainer Grimm: Multithreading done right? Problem: A lot to do.
  • 29. Rainer Grimm: Multithreading done right? Solution: Boss preparedCount.store(0); // atomic Worker herb(" Herb"), thread herbWork(herb); ... Worker david(" David"), thread davidWork(david); cout << "BOSS: PREPARE YOUR WORK.n " << endl; unique_lock<mutex> preparedUniqueLock( preparedMutex ); worker2BossCondVariable.wait(preparedUniqueLock,[]{ return preparedCount == 6; }); startWork= true; cout << "nBOSS: START YOUR WORK. n" << endl; doneCount.store(0); // atomic boss2WorkerCondVariable.notify_all(); unique_lock<mutex> doneUniqueLock( doneMutex ); worker2BossCondVariable.wait(doneUniqueLock,[]{ return doneCount == 6; }); goHome= true; cout << "nBOSS: GO HOME. n" << endl; boss2WorkerCondVariable.notify_all(); // join all Worker
  • 30. Rainer Grimm: Multithreading done right? Solution: Worker struct Worker{ Worker(string n):name(n){}; void operator() (){ int prepareTime= getRandomTime(500,2000); this_thread::sleep_for(milliseconds(prepareTime)); preparedCount++; cout << name << ": " << "Work prepared after " << prepareTime << " milliseconds." << endl; worker2BossCondVariable.notify_one(); { // wait for the boss unique_lock<mutex> startWorkLock( startWorkMutex ); boss2WorkerCondVariable.wait( startWorkLock,[]{ return startWork;}); } int workTime= getRandomTime(200,400); this_tread::sleep_for(milliseconds(workTime)); doneCount++; cout << name << ": " << "Work done after " << workTime << " milliseconds." << endl; worker2BossCondVariable.notify_one(); { // wait for the boss unique_lock<mutex> goHomeLock( goHomeMutex ); boss2WorkerCondVariable.wait( goHomeLock,[]{ return goHome;}); } } .... Use Tasks.
  • 31. Rainer Grimm: Multithreading done right? Promise and Futures • Are channels between a Sender and a Receiver • The Producer puts a value in the channel, the Consumer is waiting for • The Sender is called Promise, the Receiver Future
  • 32. Rainer Grimm: Multithreading done right? Promise and Futures: A little bit of background. • implicit with std::async • explicit with std::future and std::promise int a= 2000; int b= 11; future<int> sumFuture= async([=]{ return a+b; }); sumFuture.get(); // 2011 void sum(promise<int>&& intProm, int x, int y){ intProm.set_value(x+y); } promise<int> sumPromise; future<int> futRes= sumPromise.get_future(); thread sumThread(&sum, move(sumPromise),a,b); futRes.get(); // 2011
  • 33. Rainer Grimm: Multithreading done right? Problem: A lot to do.
  • 34. Rainer Grimm: Multithreading done right? Solution: Boss promise<void> startWorkProm; promise<void> goHomeProm; shared_future<void> startWorkFut= startWorkProm.get_future(); shared_future<void> goHomeFut= goHomeProm.get_future(); promise<void> herbPrepared; future<void> waitForHerbPrepared= herbPrepared.get_future(); promise<void> herbDone; future<void> waitForHerbDone= herbDone.get_future(); Worker herb(" Herb"); thread herbWork(herb,move(herbPrepared),startWorkFut,move(herbDone),goHomeFut); ... cout << "BOSS: PREPARE YOUR WORK.n " << endl; waitForHerbPrepared.wait(), waitForScottPrepared.wait(), waitFor ... cout << "nBOSS: START YOUR WORK. n" << endl; startWorkProm.set_value(); waitForHerbDone.wait(), waitForScottDone.wait(), waitFor ... cout << "nBOSS: GO HOME. n" << endl; goHomeProm.set_value(); // join all Worker
  • 35. Rainer Grimm: Multithreading done right? Solution: Worker struct Worker{ Worker(string n):name(n){}; void operator() (promise<void>&& preparedWork, shared_future<void> boss2WorkerStartWork, promise<void>&& doneWork, shared_future<void>boss2WorkerGoHome ){ int prepareTime= getRandomTime(500,2000); this_thread::sleep_for(milliseconds(prepareTime)); preparedWork.set_value(); cout << name << ": " << "Work prepared after " << prepareTime << " milliseconds." << endl; boss2WorkerStartWork.wait(); int workTime= getRandomTime(200,400); this_thread::sleep_for(milliseconds(workTime)); doneWork.set_value(); cout << name << ": " << "Work done after " << workTime << " milliseconds." << endl; boss2WorkerGoHome.wait(); } private: string name; };
  • 36. Rainer Grimm: Multithreading done right? Memory Model • The Memory Model deals with • atomic operations • partial ordering of operations • visible effect of operations
  • 37. Rainer Grimm: Multithreading done right? Problems? int x= 0; int y= 0; void writing(){ x= 2000; y= 11; } void reading(){ cout << "y: " << y << " "; cout << "x: " << x << endl; } int main(){ thread thread1(writing); thread thread2(reading); thread1.join(); thread2.join(); }; y x Yes 0 0 11 0 0 2000 11 2000
  • 38. Rainer Grimm: Multithreading done right? Solution: Mutex int x= 0; int y= 0; mutex mut; void writing(){ lock_guard<mutex> guard(mut); x= 2000; y= 11; } void reading(){ lock_guard<mutex> guard(mut) cout << "y: " << y << " "; cout << "x: " << x << endl; } ... thread thread1(writing); thread thread2(reading); y x Yes 0 0 11 0 0 2000 11 2000
  • 39. Rainer Grimm: Multithreading done right? Solution: Atomic atomic<int> x= 0; atomic<int> y= 0; void writing(){ x.store(2000); y.store(11); } void reading(){ cout << y.load() << " "; cout << x.load() << endl; } ... thread thread1(writing); thread thread2(reading); y x Yes 0 0 11 0 0 2000 11 2000
  • 40. Rainer Grimm: Multithreading done right? Solution: Atomic with acquire release semantic atomic<int> x= 0; atomic<int> y= 0; void writing(){ x.store(2000,memory_order_relaxed); y.store(11, memory_order_release); } void reading(){ cout << y.load(memory_order_acquire) << " "; cout << x.load(memory_order_relaxed) << endl; } ... thread thread1(writing); thread thread2(reading); y x Yes 0 0 11 0 0 2000 11 2000
  • 41. Rainer Grimm: Multithreading done right? Solution: Atomic with sychronization of non atomics int x= 0; atomic<int> y= 0; void writing(){ x= 2000; y.store(11, memory_order_release); } void reading(){ cout << y.load(memory_order_acquire) << " "; cout << x << endl; } ... thread thread1(writing); thread thread2(reading); y x Yes 0 0 11 0 0 2000 11 2000
  • 42. Rainer Grimm: Multithreading done right? Solution: Atomic with relaxed semantik atomic<int> x= 0; atomic<int> y= 0; void writing(){ x.store(2000,memory_order_relaxed); y.store(11, memory_order_relaxed); } void reading(){ cout << y.load(memory_order_relaxed) << " "; cout << x.load(memory_order_relaxed) << endl; } ... thread thread1(writing); thread thread2(reading); y x Yes 0 0 11 0 0 2000 11 2000
  • 43. Rainer Grimm: Multithreading done right? Solution: Singleton with Atomics class MySingleton{ static mutex myMutex; static atomic<MySingleton*> instance; public: static MySingleton* getInstance(){ MySingleton* sin= instance.load(); instance.load(memory_order_acquire); if ( !sin ){ lock_guard<mutex> myLock(myMutex); if( !sin ){ sin= new MySingleton(); instance.store(sin); instance.store(sin,memory_order_release); } } return sin; } ... Sequentially Consistent Acquire-Release
  • 44. Rainer Grimm: Multithreading done right? The Solution : CppMem CppMem
  • 45. Rainer Grimm: Multithreading done right? Thank you for your attention Rainer Grimm Metrax GmbH www.primedic.com Phone +49 (0)741 257-0 Rainer.Grimm@primedic.com