Calcul multithread en C++ - fil

Transcription

Calcul multithread en C++ - fil
Calcul multithread en C++
Adrien Poteaux et Alexandre Sedoglavic
FIL, Université Lille 1
Year 2014-2015
This work is licensed under a Creative Commons Attribution-ShareAlike
3.0 Unported License.
http://creativecommons.org/licenses/by-nc-sa/3.0/
[email protected]
multithread en C++
1 / 13
Objectifs (et prérequis)
Objectif : multithread en C++
→ illustré sur un exemple : évaluation / interpolation.
Calculer F = G ∗ H (polynômes de degré n)
1
Évaluation de F et G en n + 1 points
=⇒ un thread par évaluation
2
Multiplication F (α) = G (α) ∗ H(α) pour chaque point α
=⇒ un thread par multiplication (GMP)
3
Interpolation pour obtenir F
=⇒ un thread pour calculer chaque φi + une somme
Suit la partie thread de PdS.
[email protected]
multithread en C++
2 / 13
Préambule : options de compilation
CPP
= g++
CXXFLAGS = -Wall -std=c++11
LDFLAGS = -pthread
%.o : %.cpp
$(CPP) $(CXXFLAGS) -c -o $@ $<
%.out: %.o
$(CPP) -o $@ $^ $(LDFLAGS)
.PHONY: clean fclean
clean:
-rm *.o *~
fclean: clean
-rm *.out
[email protected]
multithread en C++
3 / 13
Rappel des threads en C
#include <pthread.h>
int pthread_create(pthread_t *th, const pthread_attr_t *attr,
void *(*fct) (void *), void *arg);
pthread_join, pthread_detache...
Un unique type de fonction - void* fct(void*);
Conversions obligatoires,
C++: tout type de fonction ; l’interface “fait le boulot”
[email protected]
multithread en C++
4 / 13
Lancer une fonction dans un nouveau thread en C++
#include <thread>
#include <iostream>
void my_thread_func(){
std::cout<<"hello"<<std::endl;
return ;
}
int main(){
std::thread t;
t=std::thread(my_thread_func);
t.join();
return 0;
}
(ou: std::thread t(my_thread_func);)
[email protected]
multithread en C++
5 / 13
Passer des arguments à la fonction
#include <thread>
#include <iostream>
#include <string>
void greetings(std::string const& message){
std::cout<<message<<std::endl;
return ;
}
int main(){
std::thread t(greetings,"hi !");
t.join();
return 0;
}
Autres possibilités (non détaillées ici) :
Utilisation de std::bind,
Utilisation de classes contenant un opérateur (la fonction)
...
[email protected]
multithread en C++
6 / 13
Plusieurs arguments. . .
C’est la même chose !
#include <thread>
#include <iostream>
void print_somme(int x,int y){
std::cout<<x<<" + "<<y<<" = "<<(x+y)<<std::endl;
}
int main(){
std::thread t(print_somme,123,456);
t.join();
}
Seule limite. . . celle du compilateur !
[email protected]
multithread en C++
7 / 13
Classes et threads
class SayHello{
public:
void operator()() const{
std::cout<<"hello"<<std::endl;
}
};
std::thread t(SayHello());
=⇒ pas une déclaration de thread mais de fonction !
Déclaration d’un thread (par exemple) :
int main(){
SayHello f;
std::thread t(f);
t.join();
}
[email protected]
multithread en C++
8 / 13
Fonction définie dans une classe
Similaire : on fournit
un pointeur vers la fonction membre,
un pointeur sur les objets
les éventuels paramètres
#include <thread>
#include <iostream>
class SayHello{
public:
void greeting(std::string const& message) const{
std::cout<<message<<std::endl;
}
};
int main(){
SayHello x;
std::thread t(&SayHello::greeting,&x,"goodbye");
t.join();
return 0;
}
[email protected]
multithread en C++
9 / 13
Utilisation de références
#include <thread>
#include <iostream>
#include <functional> // for std::ref
class MonAdresse{
public:
void operator()() const{
std::cout<<"Je suis "<<this<<std::endl;
}
};
Une exécution de ce code :
int main(){
MonAdresse x;
x();
std::thread t(std::ref(x));
t.join();
std::thread t2(x);
t2.join();
return 0
}
[email protected]
$ ./ref-cl.out
Je suis 0x7fff78fbf61f
Je suis 0x7fff78fbf61f
Je suis 0x1639040
multithread en C++
10 / 13
Un autre exemple...
void increment(int& i){
++i;
}
int main(){
int x=42;
std::thread t(increment,std::ref(x));
t.join();
std::cout<<"x="<<x<<std::endl;
}
(imprime 43).
[email protected]
multithread en C++
11 / 13
Protection de l’accès aux variables
Comme en PdS, il faut y faire attention ! (mutex. . . )
#include <mutex>
std::mutex m;
unsigned counter=0;
unsigned increment(){
std::lock_guard<std::mutex> lk(m);
return ++counter;
}
unsigned query(){
std::lock_guard<std::mutex> lk(m);
return counter;
}
Constructeur verouille le mutex ; destructeur le déverouille.
En général : m.lock, m.unlock. . .
lock_guard gère les exceptions de sécurité.
[email protected]
multithread en C++
12 / 13
Pour faire plus que lock_guard
std::unique_lock<> permet de :
définir une instance sans mutex associé,
définir une instance avec mutex qui reste déverouillé
faire un try lock,
gestion des mutex temporels,
acquérir (si possible) le mutex d’une autre instance,
déverouiller un mutex (celui de l’instance),
transfert de mutex,
...
[email protected]
multithread en C++
13 / 13

Documents pareils