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:04]
bmonsuez [Question n°3]
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++) 
 +    { 
 +       ​delete *it; 
 +    } 
 +
 +</​code>​
  
- // Execute both threads in parallel +Et nous testons avec le code suivant ​:
- 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); +<code cpp>
-        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() +auto graphicalObjects = createGraphicalObjects(10); 
-+drawGraphicalObjects(graphicalObjects); 
- std::​vector<​int>​ array+deleteGraphicalObjects(graphicalObjects);
- initialize_array(array, 10000, 100); +
- test_valid_execution(array); +
-}+
  
 </​code>​ </​code>​
  
-</​hidden>​+===== Question n°1 =====
  
- +Justifier la sortie produite à l’écran ​Est-ce ​que c’est le comportement désiré ?
-===== 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>​ <hidden Correction>​
  
-Nous modifions ​le code pour cette fois-ci exécuter les deux fonctions en parallèle.+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.
  
-<code cpp> +</hidden>
-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 +===== Question n°2 =====
- 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()));​ +Proposer une modification pour obtenir le comportement souhaité
- if (referenceMaxValue != maxValue) +
- std::cout << "Error when computing the max value: " << maxValue << " found, " << referenceMaxValue << " expected";​ +
-}+
  
-int main() +Tester après cette modification.
-+
- std::​vector<​int>​ array; +
- initialize_array(array,​ 10000, 100); +
- test_valid_execution(array);​ +
-+
-</​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.+<hidden Correction>​
  
-</​hidden>​ +Nous déclarons le destructeur dans la classe de base comme étant virtuel.
-===== 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. 
-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> <code cpp>
-#include <​iostream> ​      ​// std::cout +class GraphicalObject  
-#​include ​<thread> ​        // std::thread +
-#include <​mutex> ​         // std::mutex, std::​unique_lock+    public: ​      ​ 
 +       ​virtual void draw () const = 0 ;  
 +       ​~GraphicalObject() { std::cout << "& Delete GraphicalObject \n"; } 
 +        
 +};
  
-std::mutex mtx          // mutex fournissant le mécanisme d’exclusion mutuelle.+class Line: public GraphicalObject  
 +
 +    public: 
 +       ​virtual void draw () const { std::cout << "​Line";​ } ;  
 +       ​~Line() { std::cout << "​Delete Line\n";​ } 
 +        
 +};
  
-void my_function ​(int n, char c) { +class Circle: public GraphicalObject  
- // section critique, tant que l'​objet lck existe, personne ne pourra +
- // accéder à mtx. +    public: 
- std::unique_lock<std::mutex> lck(mtx)+       ​virtual ​void draw() const { std::cout << " Circle";​ } ;  
- // Code s'​exécutant. +       ​~Circle ​ () { std::cout << "​Delete Circle ​ \n"} 
-}+       
 +};
 </​code>​ </​code>​
  
-==== Question n°3.1 ====  +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.
-Modifier les fonctions  +
-<code cpp> +
-int array_find_max(std::​vector<​int>&​ theArrayint* theMaxValue) +
-</​code>​ +
- +
-et  +
- +
-<code cpp> +
-void array_multiply_by(std::​vector<​int>&​ theArray, int theValue) +
-</​code>​ +
-pour implanter ​le mécanisme d’exclusion mutuelle propose. +
- +
-==== Question n°3.2 ==== +
-Exécuter le code et vérifier que les résultats sont dorénavant cohérents. +
- +
  
 +</​hidden>​
  
in204/tds/sujets/td8/part2.1604336683.txt.gz · Last modified: 2020/11/02 17:04 by bmonsuez