SlideShare a Scribd company logo
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

More Related Content

What's hot (20)

PDF
Non-blocking synchronization — what is it and why we (don't?) need it
Alexey Fyodorov
 
PPTX
分散式系統
acksinkwung
 
PDF
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Sergey Platonov
 
PDF
Global Interpreter Lock: Episode I - Break the Seal
Tzung-Bi Shih
 
PPTX
Async await in C++
cppfrug
 
PPTX
модели акторов в с++ миф или реальность
corehard_by
 
PDF
Silicon Valley JUG: JVM Mechanics
Azul Systems, Inc.
 
PDF
GPU Programming on CPU - Using C++AMP
Miller Lee
 
PPTX
Building High-Performance Language Implementations With Low Effort
Stefan Marr
 
PPTX
Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...
Stefan Marr
 
PDF
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
Tzung-Bi Shih
 
PPTX
Effective java - concurrency
feng lee
 
PDF
Java Concurrency Idioms
Alex Miller
 
PPT
bluespec talk
Suman Karumuri
 
PPTX
Node.js System: The Landing
Haci Murat Yaman
 
PDF
Java Concurrency Gotchas
Alex Miller
 
PPTX
How Data Flow analysis works in a static code analyzer
Andrey Karpov
 
PDF
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
PPTX
Choosing the right parallel compute architecture
corehard_by
 
PDF
.NET Multithreading and File I/O
Jussi Pohjolainen
 
Non-blocking synchronization — what is it and why we (don't?) need it
Alexey Fyodorov
 
分散式系統
acksinkwung
 
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Sergey Platonov
 
Global Interpreter Lock: Episode I - Break the Seal
Tzung-Bi Shih
 
Async await in C++
cppfrug
 
модели акторов в с++ миф или реальность
corehard_by
 
Silicon Valley JUG: JVM Mechanics
Azul Systems, Inc.
 
GPU Programming on CPU - Using C++AMP
Miller Lee
 
Building High-Performance Language Implementations With Low Effort
Stefan Marr
 
Zero-Overhead Metaprogramming: Reflection and Metaobject Protocols Fast and w...
Stefan Marr
 
Global Interpreter Lock: Episode III - cat &lt; /dev/zero > GIL;
Tzung-Bi Shih
 
Effective java - concurrency
feng lee
 
Java Concurrency Idioms
Alex Miller
 
bluespec talk
Suman Karumuri
 
Node.js System: The Landing
Haci Murat Yaman
 
Java Concurrency Gotchas
Alex Miller
 
How Data Flow analysis works in a static code analyzer
Andrey Karpov
 
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
Choosing the right parallel compute architecture
corehard_by
 
.NET Multithreading and File I/O
Jussi Pohjolainen
 

Viewers also liked (20)

PDF
Конверсия управляемых языков в неуправляемые
Platonov Sergey
 
PDF
Практика Lock-free. RealTime-сервер
Platonov Sergey
 
PDF
Конкурентные ассоциативные контейнеры
Platonov Sergey
 
ODP
Multithreading 101
Tim Penhey
 
PPTX
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Mikhail Matrosov
 
PPT
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Platonov Sergey
 
PPTX
What's New in C++ 11/14?
Dina Goldshtein
 
PDF
High quality library from scratch
Platonov Sergey
 
PPT
What's New in C++ 11?
Sasha Goldshtein
 
PDF
Beating the (sh** out of the) GIL - Multithreading vs. Multiprocessing
Guy K. Kloss
 
PDF
Debugging and Profiling C++ Template Metaprograms
Platonov Sergey
 
PPT
Intro To .Net Threads
rchakra
 
PPTX
Generics C#
Raghuveer Guthikonda
 
PPTX
Multi threading design pattern
Yan Wang
 
PDF
Address/Thread/Memory Sanitizer
Platonov Sergey
 
PDF
C# Advanced L04-Threading
Mohammad Shaker
 
PPTX
Multithreading Design Patterns
PostSharp Technologies
 
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Platonov Sergey
 
PDF
Дмитрий Копляров , Потокобезопасные сигналы в C++
Sergey Platonov
 
PPTX
Threading in C#
Medhat Dawoud
 
Конверсия управляемых языков в неуправляемые
Platonov Sergey
 
Практика Lock-free. RealTime-сервер
Platonov Sergey
 
Конкурентные ассоциативные контейнеры
Platonov Sergey
 
Multithreading 101
Tim Penhey
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Mikhail Matrosov
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Platonov Sergey
 
What's New in C++ 11/14?
Dina Goldshtein
 
High quality library from scratch
Platonov Sergey
 
What's New in C++ 11?
Sasha Goldshtein
 
Beating the (sh** out of the) GIL - Multithreading vs. Multiprocessing
Guy K. Kloss
 
Debugging and Profiling C++ Template Metaprograms
Platonov Sergey
 
Intro To .Net Threads
rchakra
 
Multi threading design pattern
Yan Wang
 
Address/Thread/Memory Sanitizer
Platonov Sergey
 
C# Advanced L04-Threading
Mohammad Shaker
 
Multithreading Design Patterns
PostSharp Technologies
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Platonov Sergey
 
Дмитрий Копляров , Потокобезопасные сигналы в C++
Sergey Platonov
 
Threading in C#
Medhat Dawoud
 
Ad

Similar to Multithreading done right (20)

PPTX
Medical Image Processing Strategies for multi-core CPUs
Daniel Blezek
 
PDF
40d5984d819aaa72e55aa10376b73bde_MIT6_087IAP10_lec12.pdf
SagarYadav642223
 
PPTX
Synchronizing Concurrent Operations in C++.pptx
emsResulzade1
 
PPTX
17. thread and deadlock
Vahid Heidari
 
PPTX
Parallel Computing - openMP -- Lecture 5
arnabsahuyspm
 
PPTX
Threads and multi threading
Antonio Cesarano
 
PDF
System Programming - Threading
HelpWithAssignment.com
 
PPT
Shared Memory Programming with Pthreads (1).ppt
MALARMANNANA1
 
PDF
C++11 concurrency
xu liwei
 
PDF
Giorgio zoppi cpp11concurrency
Giorgio Zoppi
 
PPTX
Shared Memory Programming with Pthreads and OpenMP
Dilum Bandara
 
PPT
Chap7 slides
BaliThorat1
 
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
PDF
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
yaevents
 
PDF
Consider the fork_examplec code under Example code for pr.pdf
abinayamobiles
 
PDF
chap7_slidesforparallelcomputingananthgrama
doomzday27
 
PDF
Introduction to OpenMP
Akhila Prabhakaran
 
PDF
Options and trade offs for parallelism and concurrency in Modern C++
Satalia
 
PPT
10 Multicore 07
timcrack
 
Medical Image Processing Strategies for multi-core CPUs
Daniel Blezek
 
40d5984d819aaa72e55aa10376b73bde_MIT6_087IAP10_lec12.pdf
SagarYadav642223
 
Synchronizing Concurrent Operations in C++.pptx
emsResulzade1
 
17. thread and deadlock
Vahid Heidari
 
Parallel Computing - openMP -- Lecture 5
arnabsahuyspm
 
Threads and multi threading
Antonio Cesarano
 
System Programming - Threading
HelpWithAssignment.com
 
Shared Memory Programming with Pthreads (1).ppt
MALARMANNANA1
 
C++11 concurrency
xu liwei
 
Giorgio zoppi cpp11concurrency
Giorgio Zoppi
 
Shared Memory Programming with Pthreads and OpenMP
Dilum Bandara
 
Chap7 slides
BaliThorat1
 
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
Как мы охотимся на гонки (data races) или «найди багу до того, как она нашла ...
yaevents
 
Consider the fork_examplec code under Example code for pr.pdf
abinayamobiles
 
chap7_slidesforparallelcomputingananthgrama
doomzday27
 
Introduction to OpenMP
Akhila Prabhakaran
 
Options and trade offs for parallelism and concurrency in Modern C++
Satalia
 
10 Multicore 07
timcrack
 
Ad

More from Platonov Sergey (20)

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

Recently uploaded (20)

PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PDF
How to Hire AI Developers_ Step-by-Step Guide in 2025.pdf
DianApps Technologies
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
PDF
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
PDF
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PPTX
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PDF
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
PPTX
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PPTX
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
PDF
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
PDF
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PDF
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
How to Hire AI Developers_ Step-by-Step Guide in 2025.pdf
DianApps Technologies
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
vMix Pro 28.0.0.42 Download vMix Registration key Bundle
kulindacore
 
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pptx
Varsha Nayak
 
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 

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 [email protected]