User Tools

Site Tools


in204:tds:sujets:td8:part2

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:td8:part2 [2020/11/02 17:17]
bmonsuez [Question n°3.1]
in204:tds:sujets:td8:part2 [2022/11/18 10:49] (current)
Line 1: Line 1:
-====== ​Section critique ​======+====== ​Partie II – Destructeurs ​======
  
-[[in204:​tds:​sujets:​td8|TD8]] +Nous créons les classes suivantes ​:
- +
-===== Références===== +
- +
-[[http://​en.cppreference.com/​w/​cpp/​thread/​unique_lock|std::​unique_lock]] +
-[[http://​en.cppreference.com/​w/​cpp/​thread/​mutex|std::​mutex]] +
- +
-===== Question n°1=====  +
- +
-Nous supposons que nous avons deux fonctions, une première fonction calcule la valeur maximale d’un tableau numérique ​:+
  
 <code cpp> <code cpp>
-void array_find_max( +class GraphicalObject ​
- std::​vector<​int>::​const_iterator begin,  +
- std::​vector<​int>::​const_iterator end, int* theMaxValue)+
 { {
- if (begin != end) +    public: ​       
-+       ​virtual void draw () const ;  
- int result ​*begin+       ~GraphicalObject() { std::cout << "& Delete GraphicalObject \n"} 
- begin++; +       ​ 
- for (; begin != end; begin++) +};
- if (*begin > result) +
- result = *begin+
- *theMaxValue = result; +
- } +
-+
-</​code>​+
  
-la seconde fonction modifie le tableau en multipliant chaque valeur numérique du tableau par 2 :+class Linepublic GraphicalObject  
 +
 +    public: 
 +       ​virtual void draw () const { std::cout << "​Line";​ } ;  
 +       ​~Line() { std::cout << "​Delete Line\n";​ } 
 +        
 +};
  
-<code cpp> +class Circlepublic GraphicalObject ​
-void array_multiply_by( +
- std::​vector<​int>::​iterator begin, +
- std::​vector<​int>::​iterator end, int theValue)+
 { {
- for (; begin != endbegin++) +    public: 
- *begin *= theValue+       ​virtual void draw() const { std::cout << " Circle"​;  
-}+       ~Circle ​ () { std::cout << "​Delete Circle ​ \n"
 +      ​ 
 +};
 </​code>​ </​code>​
  
-Implanter chacune des fonctions. 
  
-<hidden Correction>​ +Nous créons le tableau d’objet suivant :
-Il suffit de recopier les fonctions dans un fichier ''​main.cpp'',​ d'​ajouter l'​inclusion ''​include<​vector>''​ et de compiler. +
-</​hidden>​ +
- +
- +
-===== Question 2 =====   +
- +
-Pour tester les fonctions, nous devons créer des tableaux de taille conséquente. Ces tableaux peuvent-être créés par soit de manière aléatoire soit de manière cycliques. Ci-dessous quelques exemples de fonctions générant des tableaux de taille ''​n''​ et ayant comme valeur des nombres entre ''​0''​ et ''​theMaxValue''​. +
-Nous souhaitons exécuter en parallèle les deux fonctions. ​+
  
 <code cpp> <code cpp>
-void initialize_array(std::​vector<​int>& theArray, ​int theSize+std::​vector<​GraphicalObject*createGraphicalObjects( 
- int theMaxValue)+    ​int theSize)
 { {
- theArray.clear();​ +    std::​vector<​GraphicalObject*>​ graphicalObjects(theSize);​ 
-        theArray.resise(theSize);​ +    for(int i=0; i < size; i++) 
- int step = theMaxValue / 3; +    { 
- theArray[0] = 0; +       ​graphicalObjects[i] = new Line(); 
- for (int i = 1; i < theSize; i++) +       ​graphicalObjects[++i] = new Circle()
- theArray[i] = (theArray[i-1+ step) % (theMaxValue + 1);+    } 
 +    return graphicalObjects;
 } }
 </​code>​ </​code>​
-Ou + 
 +Nous définissons une fonction de dessin pour l'​ensemble des éléments  
 +dans le tableau.
  
 <code cpp> <code cpp>
-#​include<​random>​ 
  
-void initialize_random_array(std::​vector<​int>& ​theArray, int theSize, +void drawGraphicalObjects(std::​vector<​GraphicalObject*>& ​theGraphicalObjects)
- int theMaxValue)+
 { {
- static std::​mt19937 gen(1729); +    for(auto it = theGraphicalObjects.begin();  
- std::​uniform_int_distribution<> distrib(0, theMaxValue);​ +        ​it ​theGraphicalObjects.end(); it++) 
- theArray.clear(); +    { 
- for (int i = 0; i < theSize; i++) +       ​(*it)->​draw(); 
- theArray[i] = distrib(gen);+    }
 } }
 </​code>​ </​code>​
  
  
-<hidden Correction>​ 
- 
-Nous pouvons utiliser pour ce faire une fonction de test du type suivant: 
  
 +Nous créons la fonction de destruction du tableau suivante:
 <code cpp> <code cpp>
  
-void test_valid_execution(std::​vector<​int>& ​theArray)+void deleteGraphicalObjects(std::​vector<​GraphicalObject*>& ​theGraphicalObjects)
 { {
- // Get the max value of the array +    for(auto it theGraphicalObjects.begin();  
- int referenceMaxValue ​*(std::​max_element(theArray.begin(), theArray.end()))+        ​it < theGraphicalObjects.end(); ​it++
- +    { 
- // Execute both threads in parallel +       delete *it
- int maxValue+    }
-        ​array_find_max(theArray.begin(),​ theArray.end(), &​maxValue); +
- if (referenceMaxValue != maxValue+
- std::cout << "Error when computing the max value: " << maxValue << " found, " << referenceMaxValue ​ +
- +
- array_multiply_by(theArray.begin(),​ theArray.end(),​ 2)+
-        ​array_find_max(theArray.begin(),​ theArray.end(),​ &​maxValue);​ +
- if (2*referenceMaxValue != maxValue) +
- std::cout << "Error when computing the max value: " << maxValue << " found, " << 2*referenceMaxValue ​+
 } }
- 
-int main() 
-{ 
- std::​vector<​int>​ array; 
- initialize_array(array,​ 10000, 100); 
- test_valid_execution(array);​ 
-} 
- 
 </​code>​ </​code>​
  
-</​hidden>​ +Et nous testons avec le code suivant :
- +
- +
-===== Question n°3 =====  +
- +
-Nous souhaitons exécuter les deux fonctions précédents en parallèle.  +
- +
-Expliquer pourquoi les résultats ne sont pas toujours cohérents ? ie. que la valeur maximale retournée est supérieure à la valeur maximale du tableau spécifiée au montant de sa création. +
- +
-<hidden Correction>​ +
- +
-Nous modifions ​le code pour cette fois-ci exécuter les deux fonctions en parallèle.+
  
 <code cpp> <code cpp>
-void test_valid_execution(std::​vector<​int>&​ theArray) 
-{ 
- // Get the max value of the array 
- int referenceMaxValue = *(std::​max_element(theArray.begin(),​ theArray.end()));​ 
  
- // Execute both threads in parallel +auto graphicalObjects = createGraphicalObjects(10); 
- int maxValue; +drawGraphicalObjects(graphicalObjects); 
- std::​thread max_proc(&​array_find_max,​ theArray.begin(), theArray.end(),​ &​maxValue); +deleteGraphicalObjects(graphicalObjects);
- array_multiply_by(theArray.begin(),​ theArray.end(),​ 2); +
- max_proc.join();+
  
- int modifiedMaxValue = *(std::​max_element(theArray.begin(),​ theArray.end()));​ 
- if (referenceMaxValue != maxValue) 
- std::cout << "Error when computing the max value: " << maxValue << " found, " << referenceMaxValue << " expected";​ 
-} 
- 
-int main() 
-{ 
- std::​vector<​int>​ array; 
- initialize_array(array,​ 10000, 100); 
- test_valid_execution(array);​ 
-} 
 </​code>​ </​code>​
  
-Cependant, nous constatons que la fonction ''​array_find_max''​ retourne toujours une valeur maximale plus grande que celle qui était attendue. En fait, les deux fonctions ''​array_find_max''​ et ''​multiply_array_by''​ accède au même tableau, donc les valeurs accédées par ''​array_find_max''​ peuvent avoir été modifiées par ''​multiply_array_by''​ et donc être plus grandes ou plus petites que les valeurs initialement présentes dans le tableau. On ne doit pas autoriser un accès en lecture et en écriture au tableau en même temps.+===== Question n°1 =====
  
-</​hidden>​ +Justifier la sortie produite à l’écran ? Est-ce que c’est le comportement désiré ?
-===== Question n°4 ===== +
  
-Il faut utiliser un verrou qui permet à une méthode de se garantir l’exclusivité de l’usage du tableau. Pour ce faire, nous pouvons utiliser un objet std::mutex qui encapsule un mécanisme d’exclusion mutuelle. +<hidden Correction>​
-L’objet [[http://​en.cppreference.com/​w/​cpp/​thread/​unique_lock|std::​unique_lock]] permet d’obtenir un accès exclusif sur un object [[http://​en.cppreference.com/​w/​cpp/​thread/​mutex|std::​mutex]]. Quand nous écrivons le code suivant :+
  
-<code cpp> +Le destructeur appellé est celui de l'​objet de base. Nous souhaitons appeller le destructeur de l'​objet véritablement détruit et non celui de l'​objet de base.
-#include <​iostream> ​      // std::cout +
-#include <​thread> ​        // std::​thread +
-#include <​mutex> ​         // std::mutex, std::​unique_lock+
  
-std::mutex mtx;           // mutex fournissant le mécanisme d’exclusion mutuelle.+</hidden>
  
-void my_function (int n, char c) { +===== Question n°2 =====
- // section critique, tant que l'​objet lck existe, personne ne pourra +
- // accéder à mtx. +
- std::​unique_lock<​std::​mutex>​ lck(mtx); +
- // Code s'​exécutant. +
-+
-</​code>​+
  
-==== Question n°3.1 ====  +Proposer une modification pour obtenir le comportement souhaité
-Modifier les fonctions  +
-<code cpp> +
-int array_find_max(std::​vector<​int>&​ theArray, int* theMaxValue) +
-</​code>​+
  
-et  +Tester après cette modification.
- +
-<code cpp> +
-void array_multiply_by(std::​vector<​int>&​ theArray, int theValue) +
-</​code>​ +
-pour implanter le mécanisme d’exclusion mutuelle propose.+
  
 <hidden Correction>​ <hidden Correction>​
  
-Nous insérons simplement un objet ''​vector_mutex''​ et nous ajoutons avant toute exécution ​dans les deux fonctions ​la demande d'un verrour sur la ''​mutex''​ protégeant le tableau. +Nous déclarons le destructeur ​dans la classe de base comme étant virtuel.
-<code cpp>+
  
-#​include<​vector>​ 
-#​include<​random>​ 
-#​include<​algorithm>​ 
-#​include<​thread>​ 
-#​include<​iostream>​ 
-#include <​mutex> ​         ​ 
  
-std::mutex vector_mutex;​ +<code cpp
- +class GraphicalObject ​
-void array_find_max( +
- std::​vector<int>::​const_iterator begin, ​ +
- std::​vector<​int>::​const_iterator end, int* theMaxValue)+
 { {
- std::​unique_lock<​std::​mutex>​ lock(vector_mutex);​ +    public      ​ 
- if (begin != end) +       virtual void draw () const ;  
-+       ~GraphicalObject() { std::cout << "& Delete GraphicalObject \n"} 
- int result ​*begin+       ​ 
- begin++; +};
- for (; begin != end; begin++) +
- if (*begin > result) +
- result = *begin+
- *theMaxValue = result; +
- } +
-}+
  
-void array_multiply_by( +class Linepublic GraphicalObject ​
- std::​vector<​int>::​iterator begin, +
- std::​vector<​int>::​iterator end,  +
- int theValue)+
 { {
- std::unique_lock<​std::mutex> lock(vector_mutex)+    public: 
- for (; begin != end; begin++) +       ​virtual void draw () const { std::cout << "​Line";​ } ;  
- *begin *= theValue+       ~Line() { std::cout << "​Delete Line\n"​
-}+        
 +};
  
-void initialize_array(std::​vector<​int>&​ theArray, int theSize, +class Circlepublic GraphicalObject ​
- int theMaxValue)+
 { {
- theArray.clear(); +    public: 
- theArray.resize(theSize); +       ​virtual void draw() const { std::cout << " Circle";​ } ;  
- int step = theMaxValue / 3; +       ~Circle  ​() { std::cout << "​Delete Circle ​ \n"} 
- theArray[0] = 0+       
- for (int i = 1; i theSize; i++) +}
- theArray[i] = (theArray[i - 1] + step) % (theMaxValue + 1); +</code>
-}+
  
-void initialize_random_array(std::​vector<​int>&​ theArrayint theSize, +Désormaisc'est bien le destructeur de l'​objet qui est détruit qui est appellé et pas uniquement le destructeur de la classe de base.
- int theMaxValue) +
-+
- static std::​mt19937 gen(1729);​ +
- std::​uniform_int_distribution<>​ distrib(0, theMaxValue);​ +
- theArray.clear(); +
- for (int i = 0; i < theSize; i++) +
- theArray[i] = distrib(gen);​ +
-}+
  
-void test_valid_execution(std::​vector<​int>&​ theArray) 
-{ 
- std::mutex mutex; 
- // Get the max value of the array 
- int referenceMaxValue = *(std::​max_element(theArray.begin(),​ theArray.end()));​ 
- 
- // Execute both threads in parallel 
- int maxValue; 
- std::​thread max_proc(&​array_find_max,​ theArray.begin(),​ theArray.end(),​ &​maxValue);​ 
- array_multiply_by(theArray.begin(),​ theArray.end(),​ 2); 
- max_proc.join();​ 
- 
- int modifiedMaxValue = *(std::​max_element(theArray.begin(),​ theArray.end()));​ 
- if (referenceMaxValue != maxValue) 
- std::cout << "Error when computing the max value: " << maxValue << " found, " << referenceMaxValue << " expected";​ 
-} 
- 
-int main() 
-{ 
- std::​vector<​int>​ array; 
- initialize_array(array,​ 10000, 100); 
- test_valid_execution(array);​ 
-} 
- 
-</​code>​ 
 </​hidden>​ </​hidden>​
- 
-==== Question n°3.2 ==== 
-Exécuter le code et vérifier que les résultats sont dorénavant cohérents. 
- 
- 
- 
  
in204/tds/sujets/td8/part2.1604337420.txt.gz · Last modified: 2020/11/02 17:17 by bmonsuez