SlideShare a Scribd company logo
1 of 17
Introduction au 
lock-free programming 
avec std::atomics 
Meetup C++ 
25 novembre 2014 
Montpellier 
Cyril Comparon
Multi-tasking 
Concurrence 
Le système est composé de plusieurs tâches s’exécutant de manière (partiellement) 
indépendante. 
Parallélisme 
Ces tâches peuvent en plus s’exécuter au même moment. 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Multi-tasking 
Multi-threading 
Les différentes tâches sont des exécutions distinctes du même programme, partageant le même 
espace mémoire. 
thread1 thread2 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Multi-tasking 
Multi-threading 
Les différentes tâches sont des exécutions distinctes du même programme, partageant le même 
espace mémoire. 
thread1 thread2 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Multi-tasking 
Thread-safety 
Une structure de donnée partagée est thread-safe si elle garantit un fonctionnement prédictible 
et reste dans un état valide (non corrompu) quel que soit l’ordre d’appel de ses méthodes. 
Plusieurs implémentations possibles: 
- Re-entrancy, thread-local storage, immutable objects  outils/work-arounds 
- Mutual exclusion 
- Atomic operations 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Compteur non thread-safe 
class Count 
{ 
public: 
Count() 
: m_val(0) 
{} 
int value() const 
{ 
return m_val; 
} 
void add(int v) 
{ 
m_val += v; 
} 
private: 
int m_val; 
}; 
#include <iostream> 
#include <future> 
Count count; 
void incrementer() 
{ 
for(int i=0; i<20000000; i++) 
count.add(1); 
} 
void decrementer() 
{ 
for(int i=0; i<10000000; i++) 
count.add(-2); 
} 
void main() 
{ 
std::future<void> future1(std::async(incrementer)); 
std::future<void> future2(std::async(decrementer)); 
future1.wait(); 
future2.wait(); 
std::cout << "Val = " << count.value() << std::endl; 
}
Compteur thread-safe avec un mutex 
#include <mutex> 
class Count 
{ 
public: 
Count() : m_val(0) {} 
int value() const 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
return m_val; 
} 
void add(int v) 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
m_val += v; 
} 
private: 
mutable std::mutex m_mutex; 
int m_val; 
}; 
#include <iostream> 
#include <future> 
Count count; 
void incrementer() 
{ 
for(int i=0; i<20000000; i++) 
count.add(1); 
} 
void decrementer() 
{ 
for(int i=0; i<10000000; i++) 
count.add(-2); 
} 
void main() 
{ 
std::future<void> future1(std::async(incrementer)); 
std::future<void> future2(std::async(decrementer)); 
future1.wait(); 
future2.wait(); 
std::cout << "Val = " << count.value() << std::endl; 
}
principales opérations atomiques de std::atomics 
En C++11, principalement trois opérations atomiques ont été standardisées, car le plus souvent 
supportées par le hardware : 
int exchange(int desired) 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014 
Atomically replaces the underlying value with desired. 
The operation is read-modify-write operation. 
bool compare_exchange(int &expected, 
int desired) 
a.k.a CAS 
Atomically compares the value stored in *this with the 
value pointed to by expected, and if those are equal, 
replaces the former with desired (performs read-modify- 
write operation). Otherwise, loads the actual 
value stored in *this into *expected (performs load 
operation). 
int fetch_add(int incr) 
Atomically replaces the current value with the result of 
arithmetic addition of the value and incr. The operation 
is read-modify-write operation.
Compteur thread-safe avec un mutex 
#include <mutex> 
class Count 
{ 
public: 
Count() : m_val(0) {} 
int value() const 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
return m_val; 
} 
void add(int v) 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
m_val += v; 
} 
private: 
mutable std::mutex m_mutex; 
int m_val; 
}; 
#include <iostream> 
#include <future> 
Count count; 
void incrementer() 
{ 
for(int i=0; i<20000000; i++) 
count.add(1); 
} 
void decrementer() 
{ 
for(int i=0; i<10000000; i++) 
count.add(-2); 
} 
void main() 
{ 
std::future<void> future1(std::async(incrementer)); 
std::future<void> future2(std::async(decrementer)); 
future1.wait(); 
future2.wait(); 
std::cout << "Val = " << count.value() << std::endl; 
}
Compteur lock-free 
#include <atomic> 
class Count 
{ 
public: 
Count() : m_val(0) {} 
int value() const 
{ 
return m_val; 
} 
void add(int v) 
{ 
m_val.fetch_add(v); 
} 
private: 
std::atomic<int> m_val; 
}; 
#include <iostream> 
#include <future> 
Count count; 
void incrementer() 
{ 
for(int i=0; i<20000000; i++) 
count.add(1); 
} 
void decrementer() 
{ 
for(int i=0; i<10000000; i++) 
count.add(-2); 
} 
void main() 
{ 
std::future<void> future1(std::async(incrementer)); 
std::future<void> future2(std::async(decrementer)); 
future1.wait(); 
future2.wait(); 
std::cout << "Val = " << count.value() << std::endl; 
}
Compteur lock-free 
#include <atomic> 
class Count 
{ 
public: 
Count() : m_val(0) {} 
int value() const 
{ 
return m_val; 
} 
void add(int v) 
{ 
m_val.fetch_add(v); 
} 
private: 
std::atomic<int> m_val; 
}; 
#include <iostream> 
#include <future> 
Count count; 
void incrementer() 
{ 
for(int i=0; i<20000000; i++) 
count.add(1); 
std::cout << "Incrementer finished!" << std::endl; 
} 
void decrementer() 
{ 
for(int i=0; i<10000000; i++) 
count.add(-2); 
std::cout << “Decrementer finished!" << std::endl; 
} 
void main() 
{ 
std::future<void> future1(std::async(incrementer)); 
std::future<void> future2(std::async(decrementer)); 
future1.wait(); 
future2.wait(); 
std::cout << "Val = " << count.value() << std::endl; 
}
std::atomics<T> supporte n’importe quel type 
T std::atomic::exchange(T desired) 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
T ret = m_value; 
m_value = desired; 
return ret; 
} 
bool std::atomic::compare_exchange(T &expected, T desired) 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
if(m_value == expected) { 
m_value = desired; 
return true; 
} else { 
expected = m_value; 
return false; 
} 
} 
T std::atomic::fetch_add(T incr) 
{ 
std::lock_guard<std::mutex> lock(m_mutex); 
T ret = m_value; 
m_value += incr; 
return ret; 
} 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Conclusion 
Mutual exclusion 
Atomic operations
Questions en vrac 
Pourquoi tu me dis que c’est compliqué alors que ça a l’air tout simple ? 
Pourquoi je n’envoie pas tout sur mon GPU qui est vachement plus puissant que mon CPU et il 
paraît que tout le monde fait que ça maintenant ? 
Pourquoi on s’embête avec tout ça alors qu’il existe des langages et des outils de plus haut 
niveau qui me cachent toute la complexité ? 
Y a-t-il des application pratiques intéressantes ? 
Est-ce spécifique au C++ ? 
Autres questions ? 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Les prochaines fois 
- Bas niveau : 
• Pourquoi ça ne devrait pas marcher ? 
 Weak cache coherency, out-of-order execution 
• Pourquoi ça marche quand même ? 
 Memory ordering / memory barriers 
- Le C++11 memory model 
- Penser en termes de transactions (ACID) 
- Algorithmes lock-free un peu plus intéressants 
- Différents niveaux de lock-freedom 
- Le problème ABA 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Remerciements 
CppReference 
http://en.cppreference.com/w/cpp/atomic 
Herb Sutter – atomic<> Weapons (2012) 
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 
Herb Sutter – Lock-Free Programming 
http://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Lock-Free-Programming-or-Juggling-Razor-Blades-Part-I 
The Concurrency Kit 
http://concurrencykit.org 
Wikipedia 
http://en.wikipedia.org 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014
Remerciements 
CppReference 
http://en.cppreference.com/w/cpp/atomic 
Herb Sutter – atomic<> Weapons (2012) 
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 
Herb Sutter – Lock-Free Programming 
http://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Lock-Free-Programming-or-Juggling-Razor-Blades-Part-I 
The Concurrency Kit 
http://concurrencykit.org 
Wikipedia 
http://en.wikipedia.org 
Cyril Comparon – Meetup C++ Montpellier 25/11/2014

More Related Content

What's hot

Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieur
Fredy Fadel
 

What's hot (20)

C# et .NET : Enigmes et puzzles
C# et .NET : Enigmes  et puzzlesC# et .NET : Enigmes  et puzzles
C# et .NET : Enigmes et puzzles
 
Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieur
 
Cours de C++, en français, 2002 - Cours 2.1
Cours de C++, en français, 2002 - Cours 2.1Cours de C++, en français, 2002 - Cours 2.1
Cours de C++, en français, 2002 - Cours 2.1
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScript
 
C1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partieC1 - Langage C - ISIMA - Première partie
C1 - Langage C - ISIMA - Première partie
 
Cours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMACours de C++ / Tronc commun deuxième année ISIMA
Cours de C++ / Tronc commun deuxième année ISIMA
 
Chapitre5: Classes et objets
Chapitre5: Classes et objetsChapitre5: Classes et objets
Chapitre5: Classes et objets
 
Chap1: Cours en C++
Chap1: Cours en C++Chap1: Cours en C++
Chap1: Cours en C++
 
Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)Initiation au code : Ateliers en C# (applications desktop et mobile native)
Initiation au code : Ateliers en C# (applications desktop et mobile native)
 
Chapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en JavaChapitre 11: Expression Lambda et Référence de méthode en Java
Chapitre 11: Expression Lambda et Référence de méthode en Java
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French Course
 
Formation VBA Excel
Formation VBA ExcelFormation VBA Excel
Formation VBA Excel
 
Cours javascript v1
Cours javascript v1Cours javascript v1
Cours javascript v1
 
Chapitre4: Pointeurs et références
Chapitre4: Pointeurs et références Chapitre4: Pointeurs et références
Chapitre4: Pointeurs et références
 
Formation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procéduraleFormation C# - Cours 2 - Programmation procédurale
Formation C# - Cours 2 - Programmation procédurale
 
C# langage & syntaxe
C#   langage & syntaxeC#   langage & syntaxe
C# langage & syntaxe
 
Memo java
Memo javaMemo java
Memo java
 
Cours langage c
Cours langage cCours langage c
Cours langage c
 
Introduction à Python - Achraf Kacimi El Hassani
Introduction à Python - Achraf Kacimi El HassaniIntroduction à Python - Achraf Kacimi El Hassani
Introduction à Python - Achraf Kacimi El Hassani
 
Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++
 

Viewers also liked

Charles Avison_Raül Burillo
Charles Avison_Raül BurilloCharles Avison_Raül Burillo
Charles Avison_Raül Burillo
ximowb
 
Lamonjayelhippie
LamonjayelhippieLamonjayelhippie
Lamonjayelhippie
jmartin
 
Humour 21siecle
Humour 21siecleHumour 21siecle
Humour 21siecle
lyago
 
Revue de presse CBien
Revue de presse CBienRevue de presse CBien
Revue de presse CBien
CBien
 
PresentacióN Uruguay
PresentacióN UruguayPresentacióN Uruguay
PresentacióN Uruguay
uruinvest
 
Similitudes
SimilitudesSimilitudes
Similitudes
Bimke
 

Viewers also liked (20)

C++11 & C++14
C++11 & C++14C++11 & C++14
C++11 & C++14
 
What's New in C++ 11?
What's New in C++ 11?What's New in C++ 11?
What's New in C++ 11?
 
C# 5 versus Java 8... Quand C++ 11 s'invite à la fête
C# 5 versus Java 8... Quand C++ 11 s'invite à la fêteC# 5 versus Java 8... Quand C++ 11 s'invite à la fête
C# 5 versus Java 8... Quand C++ 11 s'invite à la fête
 
C++ Generators and Property-based Testing
C++ Generators and Property-based TestingC++ Generators and Property-based Testing
C++ Generators and Property-based Testing
 
C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)
 
#25ansAPESS. Les premiers enseignements de la plateforme régionale bétail-v...
#25ansAPESS. Les premiers enseignements de la plateforme régionale bétail-v...#25ansAPESS. Les premiers enseignements de la plateforme régionale bétail-v...
#25ansAPESS. Les premiers enseignements de la plateforme régionale bétail-v...
 
Imentra conseil - Offre IMMO-PLANNER
Imentra conseil - Offre IMMO-PLANNERImentra conseil - Offre IMMO-PLANNER
Imentra conseil - Offre IMMO-PLANNER
 
Charles Avison_Raül Burillo
Charles Avison_Raül BurilloCharles Avison_Raül Burillo
Charles Avison_Raül Burillo
 
Lamonjayelhippie
LamonjayelhippieLamonjayelhippie
Lamonjayelhippie
 
Humour 21siecle
Humour 21siecleHumour 21siecle
Humour 21siecle
 
Webinar - Réseaux Sociaux d'Entreprise
Webinar - Réseaux Sociaux d'EntrepriseWebinar - Réseaux Sociaux d'Entreprise
Webinar - Réseaux Sociaux d'Entreprise
 
Breyten Breytenbach
Breyten BreytenbachBreyten Breytenbach
Breyten Breytenbach
 
CV MARZAQ
CV MARZAQCV MARZAQ
CV MARZAQ
 
Dossier de présentation de la concession de pointe d'Armor pour La Compagnie ...
Dossier de présentation de la concession de pointe d'Armor pour La Compagnie ...Dossier de présentation de la concession de pointe d'Armor pour La Compagnie ...
Dossier de présentation de la concession de pointe d'Armor pour La Compagnie ...
 
A la manière d’Élise Gravel
A la manière d’Élise GravelA la manière d’Élise Gravel
A la manière d’Élise Gravel
 
Revue de presse CBien
Revue de presse CBienRevue de presse CBien
Revue de presse CBien
 
Flash statut n°10 juillet 2016
Flash statut n°10  juillet 2016Flash statut n°10  juillet 2016
Flash statut n°10 juillet 2016
 
PresentacióN Uruguay
PresentacióN UruguayPresentacióN Uruguay
PresentacióN Uruguay
 
Similitudes
SimilitudesSimilitudes
Similitudes
 

Similar to Introduction au lock-free programming avec std::atomics

Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
cyrilgandon
 
Environnement de développement de bases de données
Environnement de développement de bases de donnéesEnvironnement de développement de bases de données
Environnement de développement de bases de données
ISIG
 
Vbisigk
VbisigkVbisigk
Vbisigk
ISIG
 
Visual Studio 2008 Overview
Visual Studio 2008 OverviewVisual Studio 2008 Overview
Visual Studio 2008 Overview
Gregory Renard
 
javaScript(1)-2023-2024-Partie1-Mechid (1).pdf
javaScript(1)-2023-2024-Partie1-Mechid (1).pdfjavaScript(1)-2023-2024-Partie1-Mechid (1).pdf
javaScript(1)-2023-2024-Partie1-Mechid (1).pdf
mistersmile053
 

Similar to Introduction au lock-free programming avec std::atomics (20)

11-Concurrence-Section critiques.pdf
11-Concurrence-Section critiques.pdf11-Concurrence-Section critiques.pdf
11-Concurrence-Section critiques.pdf
 
Python + ansible = ♥
Python + ansible = ♥Python + ansible = ♥
Python + ansible = ♥
 
C++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in ParisC++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in Paris
 
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
 
Environnement de développement de bases de données
Environnement de développement de bases de donnéesEnvironnement de développement de bases de données
Environnement de développement de bases de données
 
C++11
C++11C++11
C++11
 
Keynote .NET 2015 : une nouvelle ère
Keynote .NET 2015 : une nouvelle èreKeynote .NET 2015 : une nouvelle ère
Keynote .NET 2015 : une nouvelle ère
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
Vert.x 3
Vert.x 3Vert.x 3
Vert.x 3
 
Ateliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduinoAteliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduino
 
Vbisigk
VbisigkVbisigk
Vbisigk
 
Asyncio: offrez des tulipes à vos entrées sorties asynchrones
Asyncio: offrez des tulipes à vos entrées sorties asynchronesAsyncio: offrez des tulipes à vos entrées sorties asynchrones
Asyncio: offrez des tulipes à vos entrées sorties asynchrones
 
Visual Studio 2008 Overview
Visual Studio 2008 OverviewVisual Studio 2008 Overview
Visual Studio 2008 Overview
 
C++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelistC++ Metaprogramming : multidimensional typelist
C++ Metaprogramming : multidimensional typelist
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelle
 
retour sur confoo2011 et Symfony2
retour sur confoo2011 et Symfony2retour sur confoo2011 et Symfony2
retour sur confoo2011 et Symfony2
 
javaScript(1)-2023-2024-Partie1-Mechid (1).pdf
javaScript(1)-2023-2024-Partie1-Mechid (1).pdfjavaScript(1)-2023-2024-Partie1-Mechid (1).pdf
javaScript(1)-2023-2024-Partie1-Mechid (1).pdf
 
Présentation LMAX Disruptor So@t
Présentation LMAX Disruptor So@tPrésentation LMAX Disruptor So@t
Présentation LMAX Disruptor So@t
 
Présentation LMAX / Disruptor
Présentation LMAX / DisruptorPrésentation LMAX / Disruptor
Présentation LMAX / Disruptor
 

Introduction au lock-free programming avec std::atomics

  • 1. Introduction au lock-free programming avec std::atomics Meetup C++ 25 novembre 2014 Montpellier Cyril Comparon
  • 2. Multi-tasking Concurrence Le système est composé de plusieurs tâches s’exécutant de manière (partiellement) indépendante. Parallélisme Ces tâches peuvent en plus s’exécuter au même moment. Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 3. Multi-tasking Multi-threading Les différentes tâches sont des exécutions distinctes du même programme, partageant le même espace mémoire. thread1 thread2 Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 4. Multi-tasking Multi-threading Les différentes tâches sont des exécutions distinctes du même programme, partageant le même espace mémoire. thread1 thread2 Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 5. Multi-tasking Thread-safety Une structure de donnée partagée est thread-safe si elle garantit un fonctionnement prédictible et reste dans un état valide (non corrompu) quel que soit l’ordre d’appel de ses méthodes. Plusieurs implémentations possibles: - Re-entrancy, thread-local storage, immutable objects  outils/work-arounds - Mutual exclusion - Atomic operations Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 6. Compteur non thread-safe class Count { public: Count() : m_val(0) {} int value() const { return m_val; } void add(int v) { m_val += v; } private: int m_val; }; #include <iostream> #include <future> Count count; void incrementer() { for(int i=0; i<20000000; i++) count.add(1); } void decrementer() { for(int i=0; i<10000000; i++) count.add(-2); } void main() { std::future<void> future1(std::async(incrementer)); std::future<void> future2(std::async(decrementer)); future1.wait(); future2.wait(); std::cout << "Val = " << count.value() << std::endl; }
  • 7. Compteur thread-safe avec un mutex #include <mutex> class Count { public: Count() : m_val(0) {} int value() const { std::lock_guard<std::mutex> lock(m_mutex); return m_val; } void add(int v) { std::lock_guard<std::mutex> lock(m_mutex); m_val += v; } private: mutable std::mutex m_mutex; int m_val; }; #include <iostream> #include <future> Count count; void incrementer() { for(int i=0; i<20000000; i++) count.add(1); } void decrementer() { for(int i=0; i<10000000; i++) count.add(-2); } void main() { std::future<void> future1(std::async(incrementer)); std::future<void> future2(std::async(decrementer)); future1.wait(); future2.wait(); std::cout << "Val = " << count.value() << std::endl; }
  • 8. principales opérations atomiques de std::atomics En C++11, principalement trois opérations atomiques ont été standardisées, car le plus souvent supportées par le hardware : int exchange(int desired) Cyril Comparon – Meetup C++ Montpellier 25/11/2014 Atomically replaces the underlying value with desired. The operation is read-modify-write operation. bool compare_exchange(int &expected, int desired) a.k.a CAS Atomically compares the value stored in *this with the value pointed to by expected, and if those are equal, replaces the former with desired (performs read-modify- write operation). Otherwise, loads the actual value stored in *this into *expected (performs load operation). int fetch_add(int incr) Atomically replaces the current value with the result of arithmetic addition of the value and incr. The operation is read-modify-write operation.
  • 9. Compteur thread-safe avec un mutex #include <mutex> class Count { public: Count() : m_val(0) {} int value() const { std::lock_guard<std::mutex> lock(m_mutex); return m_val; } void add(int v) { std::lock_guard<std::mutex> lock(m_mutex); m_val += v; } private: mutable std::mutex m_mutex; int m_val; }; #include <iostream> #include <future> Count count; void incrementer() { for(int i=0; i<20000000; i++) count.add(1); } void decrementer() { for(int i=0; i<10000000; i++) count.add(-2); } void main() { std::future<void> future1(std::async(incrementer)); std::future<void> future2(std::async(decrementer)); future1.wait(); future2.wait(); std::cout << "Val = " << count.value() << std::endl; }
  • 10. Compteur lock-free #include <atomic> class Count { public: Count() : m_val(0) {} int value() const { return m_val; } void add(int v) { m_val.fetch_add(v); } private: std::atomic<int> m_val; }; #include <iostream> #include <future> Count count; void incrementer() { for(int i=0; i<20000000; i++) count.add(1); } void decrementer() { for(int i=0; i<10000000; i++) count.add(-2); } void main() { std::future<void> future1(std::async(incrementer)); std::future<void> future2(std::async(decrementer)); future1.wait(); future2.wait(); std::cout << "Val = " << count.value() << std::endl; }
  • 11. Compteur lock-free #include <atomic> class Count { public: Count() : m_val(0) {} int value() const { return m_val; } void add(int v) { m_val.fetch_add(v); } private: std::atomic<int> m_val; }; #include <iostream> #include <future> Count count; void incrementer() { for(int i=0; i<20000000; i++) count.add(1); std::cout << "Incrementer finished!" << std::endl; } void decrementer() { for(int i=0; i<10000000; i++) count.add(-2); std::cout << “Decrementer finished!" << std::endl; } void main() { std::future<void> future1(std::async(incrementer)); std::future<void> future2(std::async(decrementer)); future1.wait(); future2.wait(); std::cout << "Val = " << count.value() << std::endl; }
  • 12. std::atomics<T> supporte n’importe quel type T std::atomic::exchange(T desired) { std::lock_guard<std::mutex> lock(m_mutex); T ret = m_value; m_value = desired; return ret; } bool std::atomic::compare_exchange(T &expected, T desired) { std::lock_guard<std::mutex> lock(m_mutex); if(m_value == expected) { m_value = desired; return true; } else { expected = m_value; return false; } } T std::atomic::fetch_add(T incr) { std::lock_guard<std::mutex> lock(m_mutex); T ret = m_value; m_value += incr; return ret; } Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 13. Conclusion Mutual exclusion Atomic operations
  • 14. Questions en vrac Pourquoi tu me dis que c’est compliqué alors que ça a l’air tout simple ? Pourquoi je n’envoie pas tout sur mon GPU qui est vachement plus puissant que mon CPU et il paraît que tout le monde fait que ça maintenant ? Pourquoi on s’embête avec tout ça alors qu’il existe des langages et des outils de plus haut niveau qui me cachent toute la complexité ? Y a-t-il des application pratiques intéressantes ? Est-ce spécifique au C++ ? Autres questions ? Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 15. Les prochaines fois - Bas niveau : • Pourquoi ça ne devrait pas marcher ?  Weak cache coherency, out-of-order execution • Pourquoi ça marche quand même ?  Memory ordering / memory barriers - Le C++11 memory model - Penser en termes de transactions (ACID) - Algorithmes lock-free un peu plus intéressants - Différents niveaux de lock-freedom - Le problème ABA Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 16. Remerciements CppReference http://en.cppreference.com/w/cpp/atomic Herb Sutter – atomic<> Weapons (2012) http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 Herb Sutter – Lock-Free Programming http://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Lock-Free-Programming-or-Juggling-Razor-Blades-Part-I The Concurrency Kit http://concurrencykit.org Wikipedia http://en.wikipedia.org Cyril Comparon – Meetup C++ Montpellier 25/11/2014
  • 17. Remerciements CppReference http://en.cppreference.com/w/cpp/atomic Herb Sutter – atomic<> Weapons (2012) http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 Herb Sutter – Lock-Free Programming http://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Lock-Free-Programming-or-Juggling-Razor-Blades-Part-I The Concurrency Kit http://concurrencykit.org Wikipedia http://en.wikipedia.org Cyril Comparon – Meetup C++ Montpellier 25/11/2014

Editor's Notes

  1. Me présenter
  2. Piqûre de rappel – multi-tasking - système concurrent - parallélisme
  3. Vieux mono-CPU – scheduler de l’OS – (preemptive multitasking) illusion de parallélisme – multithreading déjà très utilisé
  4. Parallélisme induit par le multi-CPU Multithreading rendu encore plus important à cause de cela
  5. Patterns proposés par wikipedia Lock-based = critical sections = blocking algos Lock-free = non-blocking algos
  6. Que va-t-il se passer et pourquoi ? Race condition ! Dépend de la température de la pièce !
  7. Ca marche ! Mais performances bof et surtout, que se passe-t-il si l’opération n’est pas triviale, fait des I/O ou a d’autres dépendances ? On peut le simuler en suspendant un thread.
  8. Ca marche ! Mais performances bof et surtout, que se passe-t-il si l’opération n’est pas triviale, fait des I/O ou a d’autres dépendances ? On peut le simuler en suspendant un thread.
  9. Obstruction-free ! = même en suspendant un des deux threads, l’autre thread finit son boulot ! (c’est une des propriétés des algorithmes lock-free)
  10. Obstruction-free ! = même en suspendant un des deux threads, l’autre thread finit son boulot ! (c’est une des propriétés des algorithmes lock-free)
  11. std::atomic<T>::is_lock_free() renseigne si T est supporté sans lock sur le hardware cible. Sur les machines les plus courantes, les entiers 32 et 64 bits et les pointeurs.
  12. Lock-based = critical sections = blocking algos = simpler but can kill scalability and induce weird behaviors (priority inversion!) Lock-free = non-blocking algos = eliminate deadlocks = eliminate/reduce blocking waiting = concurrency++ = scalability++
  13. Parce que le compilateur et le processeur et ses caches ont leurs raisons N’adresse pas le même genre de problème – embarrassingly parallel problems Parce que ça ne fait pas de mal de le savoir quand même, et parce que si déjà on fait du C++, c’est qu’on est un peu maso et qu’on cherche à tirer le max de perf/watt. De toute façon les techniques que vous allez apprendre et notamment la pensée « transactionnelle » est précieuse dans les environnements distribués bien au-delà du multithreading ! Oui, beaucoup, c’est un domaine très actif de la recherche. Plus prosaïquement, ce sont les briques de base sans lesquelles vous n’auriez meme pas vos mutexes. Non, il y a meme une API dédiée dans la lib java, c’est dire !