This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
in204:tds:sujets:td9:part1 [2021/11/06 10:15] bmonsuez |
in204:tds:sujets:td9:part1 [2022/11/18 10:49] (current) |
||
---|---|---|---|
Line 6: | Line 6: | ||
[[http://en.cppreference.com/w/cpp/thread/thread|std::thread]] | [[http://en.cppreference.com/w/cpp/thread/thread|std::thread]] | ||
- | |||
- | |||
- | ====== Partie n°1 ====== | ||
- | |||
- | Nous souhaitons mesurer le temps de calcul d'une fonction. Pour ce faire, nous souhaitons créer une fonction : | ||
- | - qui va prendre en argument la fonction que nous souhaitons exécuter, | ||
- | - les arguments que nous devons passer à cette fonction, | ||
- | - qui va lancer un chronomètre, | ||
- | - qui va lancer la fonction | ||
- | - qui va récupérer le résultat de la fonction, | ||
- | - qui va estimer le temps passé par le temps de la fonction, | ||
- | - qui va retourner à la fois le résultat de la fonction mais aussi le temps passé par la fonction. | ||
===== Question n°1 ===== | ===== Question n°1 ===== | ||
- | Pour simplifier la conception, écrivez dans un premier la fonction qui appelle la fonction factorielle qui suit: | + | Créer un processus léger qui est associé à une fonction simple. |
- | et qui va exécuter cette fonction | + | |
<code cpp> | <code cpp> | ||
- | int factorial(int n) | + | #include<iostream> |
+ | #include<thread> | ||
+ | |||
+ | void simple_method() | ||
{ | { | ||
- | return n <= 1 ? 1 : (n * factorial(n - 1)); | + | int i = 5; |
+ | int x = 10; | ||
+ | int result = i * x; | ||
+ | std::cout << "This code calculated the value " | ||
+ | << result << " from thread ID: " | ||
+ | << std::this_thread::get_id() << "\n"; | ||
} | } | ||
- | </code> | ||
- | La fonction aura le squelette suivant: | + | |
- | <code> | + | int main() |
- | int estimate_time(int n) | + | |
{ | { | ||
- | // Code pour lancer le chronomètre | + | std::thread simpleThread(&simple_method); |
- | int result = factorial(n); | + | std::cout << "Main thread is executing and waiting\n"; |
- | // Code pour calculer le temps écoulé et affiché celui-ci. | + | simpleThread.join(); |
- | return result; | + | std::cout << "Alternate thread has terminated.\n"; |
+ | return 0; | ||
} | } | ||
+ | |||
</code> | </code> | ||
- | ===== Question n°2 ===== | + | Exécuter le code et analyser la sortie. Commenter celle-ci, notamment au regard de la documentation de la classe [[http://en.cppreference.com/w/cpp/thread/thread|std::thread]]. |
- | Transformer la fonction précédente <code>estimate_time</code> pour qu'elle prenne en argument une fonction arbitraire à un argument et un résultat. | + | <hidden Correction> |
- | Il faudra penser à utiliser un modèle (template) de fonctions. | + | Un objet ''std::thread'' correspondant à un processus léger est créé et est associé au code la méthode ''simple_method''. Ce processus démarre immédiatement et lance le calcul. L'exécution du code principal se poursuit et le message ''Main thread is executing and waiting'' est affiché. La ligne suivant attend que l'exécution du processus léger associé à l'objet ''std::thread'' termine. Une fois que ce processus a terminé, l'exécution du processus principal continue, affiche le message ''Alternate thread has terminated'' et rend la main. |
- | ===== Question n°3 ===== | + | </hidden> |
- | Nous souhaitons désormais pouvoir prendre une fonction pouvant prendre plusieurs arguments comme la fonction puissance. | + | |
+ | ===== Question n°2 ===== | ||
+ | |||
+ | Ecrire un programme qui lance les deux calculs suivants en parallèle, le premier dans un processus léger secondaire, le premier dans le processus léger principal : | ||
<code cpp> | <code cpp> | ||
- | template<class T1, T2> | + | void worker_process(int numberOfIterations) |
- | T1 power(T2 x, int y) | + | |
{ | { | ||
- | T1 result = (T1)1.0 | + | for (int i = 1; i < numberOfIterations; i++) |
- | while(y-- > 0) | + | { |
- | result = result * (T1)x; | + | std::cout << "Worker Thread: " << i << "\n"; |
- | return result; | + | } |
} | } | ||
</code> | </code> | ||
- | Modifier le code de la fonction pour pouvoir prendre une telle fonction comme paramètre. | + | et |
+ | <code cpp> | ||
+ | void main_process() | ||
+ | { | ||
+ | for (int i = 1; i < 1000; i++) | ||
+ | { | ||
+ | std::cout << "Primary Thread: " << i << "\n"; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Tester le code. | ||
+ | |||
+ | <hidden Correction> | ||
- | Estimer le temps nécesaire pour calculer par exemple : 1.02 ^ 10000000. | + | Nous pouvons écrire le code suivant qui crée deux processus légers, le premier exécutant la fonction ''worker_process'' avec comme paramètre ''10000'' et le second exécutant la fonction ''main_proc''. |
+ | <code cpp> | ||
+ | int main() | ||
+ | { | ||
+ | std::thread worker_proc(&worker_process, 10000); | ||
+ | std::thread main_proc(&main_process); | ||
+ | worker_proc.join(); | ||
+ | main_proc.join(); | ||
+ | } | ||
+ | </code> | ||
- | ==== Question n°5 ==== | + | L'exécution commence par la tâche ''worker_proc'' et nous devons voir certains messages de la tâche ''main_proc'', nous voyons cependant que les messages ne sont pas très entrelacés, ce qui est du au fait que l'on alloue un temps d'utilisation de la console à chacun des deux processus légers. |
- | Créer une fonction nouvelle qui va appeller la fonction <code>estimate_time</code> pour calculer <code>x</code> fois le temps et retourné le temps moyen pour effectuer un "run" de la fonction. | + | Pour mettre un peu d'entrelacement, nous pouvons ajouter un peu de temps entre les affichaches, par exemple 1ns pour le premier processus et 10ns pour le second. Ceci nous donne le code suivant: |
- | Exécuter cette fonction pour les fonctions <code>power</code> et <code>factorial</code> précédemment définie. | + | <code cpp> |
+ | #include<iostream> | ||
+ | #include<thread> | ||
+ | #include <chrono> | ||
- | ==== Question n°4 ==== | ||
- | Que faut-il faire ajouter pour dire au compilateur que la fonction <code>factorial</code> ou que la fonction <code>power</code> peut-être exécutée au moment de l'exécution ? | ||
- | Effectuer la modification. | + | void worker_process(int numberOfIterations) |
+ | { | ||
+ | for (int i = 1; i < numberOfIterations; i++) | ||
+ | { | ||
+ | std::cout << "Worker Thread: " << i << "\n"; | ||
+ | std::this_thread::sleep_for(10ns); | ||
+ | } | ||
+ | } | ||
- | Calculer le temps pris désormais par ces fonctions. | + | void main_process() |
+ | { | ||
+ | for (int i = 1; i < 1000; i++) | ||
+ | { | ||
+ | using namespace std; | ||
+ | std::cout << "Primary Thread: " << i << "\n"; | ||
+ | std::this_thread::sleep_for(1ns); | ||
+ | } | ||
+ | } | ||
+ | int main() | ||
+ | { | ||
+ | std::thread worker_proc(&worker_process, 10000); | ||
+ | std::thread main_proc(&main_process); | ||
+ | worker_proc.join(); | ||
+ | main_proc.join(); | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||