User Tools

Site Tools


in204:tds:sujets:td9:part1

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
in204:tds:sujets:td9:part1 [2021/11/06 12:32]
bmonsuez
in204:tds:sujets:td9:part1 [2022/11/18 10:49] (current)
Line 1: Line 1:
-====== ​Partie 1 : Manipuler un ensemble d'​arguments ​======+====== ​Création & Manipulation de Processus léger ​======
  
-===== Question 1 =====+[[in204:​tds:​sujets:​td9|TD9]]
  
-Ecrire une fonction <​code>​print</​code>​ qui prend un nombre libre d'​entiers en paramètres et qui affiche ces entiers sur la console.+===== Références=====
  
-Pour ce faire, nous vous conseillons d'​autiliser la classe <​code>​std::​initializer_list<​T><​/code> comme argument de la fonction.+[[http://en.cppreference.com/​w/​cpp/​thread/​thread|std::​thread]]
  
-Un [[https://​en.cppreference.com/​w/​cpp/​utility/​initializer_list|std::​initializer_list<​T>​]] permet d'​accéder ​à la une liste de valeurs de type <​code>​T</​code>​ qui est écrit sous la forme suivante :+===== Question n°1 ===== 
 + 
 +Créer un processus léger qui est associé ​à une fonction simple.
  
 <code cpp> <code cpp>
-std::​initializer_list<intlist_of_values = {1, 3, 4, 2 }; +#include<iostream
-</code>+#include<thread>
  
-Cette liste de valeur n'est pas modifiable. Il est seulement possible de la lire en lecture comme un containeur classique. Les fonctions <​code>​begin()</​code>, ​<code>end()</code> ainsi que <code>​size()</code> permettent d'​accéder aux valeurs stockées dans la liste.+void simple_method() 
 +
 + 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";​ 
 +}
  
-<hidden Correction>​ 
  
-<code cpp> +int main()
-void print(std::​initializer_list<​int> arguments)+
 { {
-    auto it = arguments.begin(),​ + std::​thread simpleThread(&​simple_method); 
-        end_it = arguments.end(); + std::cout << ​"Main thread is executing and waiting\n"​
-    if (it != end_it) + simpleThread.join(); 
-    { + std::cout << "Alternate thread has terminated.\n"; 
-        ​std::cout << ​*it+ return 0;
-        ​while ​(++it != end_it+
-            std::cout << "" ​<< *it        +
-    }+
 } }
 +
 </​code>​ </​code>​
  
-</hidden>+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]].
  
-===== Question 2 =====+<hidden Correction>​
  
-Généraliser cette fonction ​à d'autres types que les types entiers+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.
  
- 
-Cette fois-ci, nous attaquons les choses un peu plus complexes. En effet, pour cela, vous allez utiliser les [[https://​en.cppreference.com/​w/​cpp/​language/​parameter_pack|packs de paramètres]] des fonctions et des classes templatées. 
- 
-Quand nous écrivons : 
- 
-  * <​code>​template<​class ...Args> f(Args... arguments)</​code>,​ cela signifie que la fonction prend comme arguments un ensemble d'​arguments qui ont des types différents. La variable <​code>​arguments</​code>​ fait référence à l'​ensemble des valeurs ayant chacun un type différent. 
- 
- 
- 
-<hidden Correction>​ 
 </​hidden>​ </​hidden>​
  
  
-====== Partie 2 :Mesuré le temps passé par une fonction ====== +===== Question ​n°2 =====
- +
-[[in204:​tds:​sujets:​td9|TD9]] +
- +
-===== Références===== +
- +
-[[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 =====+
  
-Pour simplifier la conceptionécrivez ​dans un premier ​la fonction qui appelle la fonction factorielle qui suit: +Ecrire un programme qui lance les deux calculs suivants en parallèlele premier ​dans un processus léger secondaire, le premier ​dans le processus léger principal ​:
-et qui va exécuter cette fonction+
  
 <code cpp> <code cpp>
-int factorial(int n)+void worker_process(int numberOfIterations)
 { {
-    return n <= 1 ? 1 (* factorial(n - 1));+ for (int i = 1; i < numberOfIterations;​ i++) 
 +
 + std::cout << "​Worker Thread: " << ​ i << "\n"; 
 + }
 } }
 </​code>​ </​code>​
  
-La fonction aura le squelette suivant: +et 
-<​code>​ +<​code ​cpp
-int estimate_time(int n)+void main_process()
 { {
-    // Code pour lancer le chronomètre + for (int 1i < 1000; i++) 
-    ​int result ​factorial(n)+ { 
-    // Code pour calculer le temps écoulé et affiché celui-ci. + std::cout << "​Primary Thread: " << i << "​\n"​; 
-    ​return result;+ }
 } }
 </​code>​ </​code>​
- +  
-===== Question n°2 ===== +Tester le code. 
- +
-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.  +
- +
-Il faudra penser à utiliser un modèle (template) de fonctions+
 <hidden Correction>​ <hidden Correction>​
  
-Il suffit de modifier la fonction antérieure comme un fonction ​qui prend deux paramètres de types: +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''​.
-  - le type correspondant à la fonction+
-  - le type correspondant au paramètre de la fonction. +
- +
-Et le tour est joué. Ceci donne le code suivant :+
  
 <code cpp> <code cpp>
-template<​class Function, class T> +int main()
-std::​pair<​std::​chrono::​high_resolution_clock::​duration,​ long double> estimate_function_time(Function function, T argument)+
 { {
- auto starting_time = std::chrono::​high_resolution_clock::​now(); + std::thread worker_proc(&​worker_process,​ 10000); 
- auto result = function(argument); + std::thread main_proc(&​main_process); 
- auto elasped_time = std::​chrono::​high_resolution_clock::​now() - starting_time+ worker_proc.join(); 
- return std::​make_pair(elasped_time,​ result);+ main_proc.join();
 } }
 </​code>​ </​code>​
  
-</​hidden>​+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.
  
 +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:
  
-===== Question n°3 =====+<code cpp> 
 +#​include<​iostream>​ 
 +#​include<​thread>​ 
 +#include <​chrono>​
  
-Nous souhaitons désormais pouvoir prendre une fonction pouvant prendre plusieurs arguments comme la fonction puissance. 
  
-<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;+ std::​this_thread::​sleep_for(10ns); 
 + }
 } }
-</​code>​ 
  
-Modifier le code de la fonction pour pouvoir prendre une telle fonction comme paramètre. +void main_process() 
- +{ 
-Estimer le temps nécesaire pour calculer par exemple : 1.02 ^ 10000000. + for (int i = 1; i < 1000; i++) 
- + { 
- + using namespace std; 
-==== Question n°5 ==== + std::​cout ​<< "Primary Thread: ​" << ​<< ​"​\n";​ 
- + std::​this_thread::​sleep_for(1ns);​ 
-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. + } 
- +}
-Exécuter cette fonction pour les fonctions ​<code>​power</code> et <code>​factorial</code> précédemment définie. +
- +
-==== 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. +
- +
-Calculer le temps pris désormais par ces fonctions.+
  
 +int main()
 +{
 + std::​thread worker_proc(&​worker_process,​ 10000);
 + std::​thread main_proc(&​main_process);​
 + worker_proc.join();​
 + main_proc.join();​
 +}
 +</​code>​
  
 +</​hidden>​
  
  
in204/tds/sujets/td9/part1.1636201944.txt.gz · Last modified: 2021/11/06 12:32 by bmonsuez