Université de Sherbrooke, développement du jeu vidéo, CPA

Vous trouverez ici quelques documents et quelques liens pouvant, je l'espère, vous être utiles.

Les documents qui vous sont fournis ici le sont pour vous rendre service.

Je travaille très fort sur chacun de mes cours. Veuillez ne pas vendre (ou donner) les documents que je vous offre ici à qui que ce soit sans mon consentement. Si des abus surviennent, je vais cesser de rendre ce matériel disponible à toutes et à tous.

Si ces documents vous rendent service, faites-le moi savoir. Mon adresse de courriel est disponible à travers la page où on trouve mon horaire.

Vous trouverez sur ce site :

Documents sous forme électronique

Cliquez sur cette cible pour le plan de cours, sous forme électronique.

Contenu des séances

Ce qui suit détaille le contenu des séances du cours INF739.

Index des séances théoriques
S00 S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14
Date Séance Contenu

Vendredi 12 janvier AM

S00

Au menu :

Notez que nous examinons dans ce cours des techniques portables vers plusieurs plateformes et plusieurs compilateurs, mais que C++ 11 offre maintenant une API pleinement portable de threading et de synchronisation. Vous en verrez un exemple ici, et je vous montrerai comment en implémenter les bases vous-mêmes si vous le souhaitez.

Cela dit, il est possible (pour ne pas dire probable) que cette API ne soit pas disponible sur certaines des plateformes que vous rencontrerez dans l'industrie, du moins à court terme. Ainsi, ne vous en faites pas : en examinant des manières de procéder sans cette API, nous ne perdons pas notre temps.

Dans les notes de cours :

  • Pour l'essentiel, ce qui a été couvert aujourd'hui apparaît dans CPA – Volume 01, pp. ≈9-41

Vendredi 19 janvier AM

S01

Au menu :

Dans les notes de cours :

  • Les objets volatiles sont expliqués dans CPA – Volume 01, pp. ≈99-123
  • Un tableau résumant les impacts du mot volatile apparaît dans CPA – Volume 01, p. 117
  • À propos de l'atomicité, voir Atomicite.pdf (document qui demande à être retravaillé, mais c'est mieux que rien)

J'ai montré un petit exemple d'implémentation réduite de std::async() à titre illustratif, acceptant une fonction int(*)(int) et un paramètre int puis retournant une future<int>. Voici une version un peu plus complète (je n'ai pas tenu compte des politiques de démarrage comme std::launch_async et std::launch_defer) :

template <class T, class F, class ... Args>
   auto async(F f, Args && ... args) -> decltype(f(std::forward<Args>(args)...)) {
      promise<T> ze_promesse;
      future<T> ze_future = ze_promesse.get_future();
      thread th{ [](promise<T>&& p, F f, Args && ... args) {
         try {
            p.set_value(f(std::forward<Args>(args)...));
         }
         catch (...) {
            p.set_exception(current_exception());
         }
      }, std::move(ze_promesse), f, std::forward<Args>(args)... };
      th.detach();
      return ze_future;
   }

Ceci ne signifie pas que votre implémentation soit écrite exactement comme ceci, mais c'est l'idée.

J'ai aussi fait une petite activité pour compter les vilains dans une carte de grande taille, en séquentiel puis en parallèle. Tel que mentionné en classe, ne faites pas circuler cet exemple (c'est un exercice que j'utilise à l'occasion quand je donne des formations en entreprise). Le code suit :

#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
#include <chrono>
#include <locale>
#include <future>
#include <random>
#include <algorithm>
#include <numeric>
using namespace std;
using namespace std::chrono;

template <class F, class ... Args>
auto tester(F f, Args &&... args) {
   auto pre = high_resolution_clock::now();
   auto res = f(std::forward<Args>(args)...);
   auto post = high_resolution_clock::now();
   return make_pair(res, post - pre);
}

enum class Case : unsigned char {
   Vide, Heros, Mur, Vilain, Bibitte
};

int main() {
   locale::global(locale{ "" });
   enum { LARGEUR = 25'000, HAUTEUR = 25'000 };
   vector<Case> carte(LARGEUR * HAUTEUR, Case::Vide);
   random_device rd;
   mt19937 prng{ rd() };
   uniform_int_distribution<int> d100{ 1,100 }, d4{ 1,4 };
   auto temps_init = tester([&] {
      generate(begin(carte), end(carte), [&] {
         return d100(prng) <= 85 ? Case::Vide :
            static_cast<Case>(d4(prng));
      });
      return 0;
   });
   cout << "Initialisation complétée en "
        << duration_cast<milliseconds>(temps_init.second).count()
        << " ms." << endl;
   cout << "Nb pas gentils (séquentiel) : ";
   auto seq = tester([&] {
      return count_if(begin(carte), end(carte), [](Case c) {
         return c == Case::Bibitte || c == Case::Vilain;
      });
   });
   cout << seq.first << " obtenu en "
        << duration_cast<milliseconds>(seq.second).count()
        << " ms." << endl;
   //
   // Ok, on y va...
   //
   cout << "Nb pas gentils (parallèle) : ";
   auto para = tester([&] {
      auto ncoeurs = thread::hardware_concurrency();
      const auto taille_bloc = carte.size() / ncoeurs;
      vector<future<int>> v;
      for (decltype(ncoeurs) i = 0; i != ncoeurs - 1; ++i)
         v.emplace_back(async([deb = begin(carte) + i * taille_bloc,
            fin = begin(carte) + (i + 1) * taille_bloc]{
            return count_if(deb, fin, [](Case c) {
               return c == Case::Bibitte || c == Case::Vilain;
            });
         }));
      auto n = count_if(begin(carte) + (ncoeurs - 1) * taille_bloc,
         end(carte), [](Case c) {
         return c == Case::Bibitte || c == Case::Vilain;
      });
      return accumulate(begin(v), end(v), n, [](int so_far, future<int> &f) {
         return so_far + f.get();
      });
   });
   cout << para.first << " obtenu en "
        << duration_cast<milliseconds>(para.second).count()
        << " ms." << endl;
}

Enfin, j'ai fait une démonstration des coûts du faux-partage (attention : compilez en 64 bits dû à la taille du vecteur). Le code suit :

#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
#include <chrono>
#include <locale>
#include <future>
#include <random>
#include <algorithm>
#include <numeric>
using namespace std;
using namespace std::chrono;

template <class F, class ... Args>
auto tester(F f, Args &&... args) {
   auto pre = high_resolution_clock::now();
   auto res = f(std::forward<Args>(args)...);
   auto post = high_resolution_clock::now();
   return make_pair(res, post - pre);
}

int main() {
   locale::global(locale{ "" });
   enum { N = 25'000 };
   vector<int> mat(N * N);
   auto taille_bloc = mat.size() / 8; // hardware_concurrency
   iota(begin(mat), end(mat), 1); // approx. la moitié est impaire
   auto r0 = tester([&] {
      int nimpairs[8]{}; // initialisés à zéro; 8 == hardware_concurrency
      vector<thread> th;
      for (int i = 0; i != 8; ++i)
         th.emplace_back([&, i, taille_bloc] {
         for (int j = i * taille_bloc; j != (i + 1) * taille_bloc; ++j)
            if (mat[j] % 2 != 0)
               nimpairs[i]++;
      });
      for (auto & thr : th) thr.join();
      return accumulate(begin(nimpairs), end(nimpairs), 0);
   });
   cout << "Par. Nb impairs au total : " << r0.first
        << " obtenu en " << duration_cast<milliseconds>(r0.second).count()
        << " ms." << endl;
   auto r1 = tester([&] {
      int nimpairs = 0;
      for (size_t j = 0; j != mat.size(); ++j)
         if (mat[j] % 2 != 0)
            nimpairs++;
      return nimpairs;
   });
   cout << "Seq. Nb impairs au total : " << r1.first
        << " obtenu en " << duration_cast<milliseconds>(r1.second).count()
        << " ms." << endl;
   auto r2 = tester([&] {
      int nimpairs[8]{}; // initialisés à zéro; 8 == hardware_concurrency
      vector<thread> th;
      for (int i = 0; i != 8; ++i)
         th.emplace_back([&, i, taille_bloc] {
            int n = 0;
            for (int j = i * taille_bloc; j != (i + 1) * taille_bloc; ++j)
               if (mat[j] % 2 != 0)
                  n++;
            nimpairs[i] = n;
         });
      for (auto & thr : th) thr.join();
      return accumulate(begin(nimpairs), end(nimpairs), 0);
   });
   cout << "Par. Nb impairs au total : " << r2.first
        << " obtenu en " << duration_cast<milliseconds>(r2.second).count()
        << " ms." << endl;
}

Mardi 23 janvier PM

S02

Au menu :

  • Q00
  • Les sockets de type flux :
    • exploration brève du modèle de programmation
    • examen rapide des distinctions entre le modèle BSD de base, qui est universel, et certaines implémentations OO construites par-dessus
    • réflexion sur les limites de ce qui peut être transigé entre deux homologues situés dans des espaces adressables distincts
    • réflexion aussi sur les distinctions structurelles entre les architectures matérielles, en particulier en ce qui a trait à la structure interne des entiers

Dans les notes de cours :

  • Les sockets de type flux sont décrits dans CPA – Volume 02, pp. ≈6-36

Vendredi 26 janvier AM

S03

Au menu, activité pratique :

  • En équipe de deux personnes, implémentez un système client/ serveur où le serveur peut gérer plusieurs clients de manière concurrente
  • Le client devra envoyer au serveur un nom de fichier (vous devez supporter à la fois les fichiers « texte » et « binaires »). Le nom peut inclure un chemin (p. ex. : "c:\machin\truc\yo man.jpeg" ou "../projet.sln"), et les répertoires relatifs seront considérés sur la base du répertoire de travail du serveur
  • Le serveur devra consommer ce nom, puis transférer le contenu du fichier en question au client
  • Le client devra consommer le contenu du fichier, et écrire ce fichier dans son propre répertoire de travail (excluant le chemin s'il y a lieu)
  • On doit pouvoir vérifier que le fichier reçu et écrit sur le poste du client est identique au fichier d'origine (ça peut être aussi simple que de l'ouvrir  )
  • Présentez à votre chic prof le code source du client et du serveur pour rétroaction sur le code (on peut faire cela en classe si vous le souhaitez)

Je serai avec vous, en soutien. L'idée ici est de s'assurer que vous êtes en mesure de bien gérer plusieurs séances concurrentes de transfert de fichiers, que vous gérez adéquatement les ressources associées à ces transactions, et que vous êtes familiarisés avec les sockets de type flux.

Mardi 30 janvier PM

S04

 

Vendredi 2 février AM

S05

 

Mardi 6 février PM

S06

 

La semaine du 12 au 16 février, notre cours fait relâche. Bon travail sur votre projet, les amis!

Mardi 20 février PM

S07

 

Vendredi 23 février AM

S08

 

Mardi 27 février PM

S09

 

Mardi 6 mars PM

S10

 

Vendredi 9 mars AM

S11

 

La semaine du 12 mars au 16 mars, notre cours fait relâche. Je serai à la rencontre du WG21 à Jacksonville; voir ../../Sujets/Orthogonal/wg21-2018-Jacksonville.html si vous voulez suivre mes aventures.

Les semaines du 19 mars, 26 mars et 2 avril, notre cours fait relâche. Bon travail sur votre projet, les amis. Prenez soin de ne pas oublier tout ce que nous avons fait jusqu'ici!

Mardi 10 avril PM

S12

 

Mardi 17 avril PM

S13

 

La semaine du 23 avril, notre cours fait relâche. Bon travail sur votre projet, les amis!

Mardi 1er mai PM

S14

Remise de L01, puis un chic examen final vous attend!

Résultats des questions quasi-hebdomadaires

Les moyennes des résultats obtenus aux questions quasi-hebdomadaires pour la session en cours suivent. Notez que l'écart-type n'est pas significatif étant donné la pondération des questions (sur cinq points, un point de différence représente , ce qui bousille quelque peu cette composante statistique).

 Question   Séance 
Q00 S??
Q01 S??
Q02 S??
Q03 S??
Q04 S??
Q05 S??
Q06 S??
Q07 S??
Q08 S??
Q09 S??
 :
(huit meilleurs) :

Consignes des livrables

Les consignes des livrables L00 et L01 suivent (dates de remise incluses).

Livrable 00

Voici les consignes du livrable L00 :

Vous constaterez que je ne vous impose pas de livraison de code. Un document bref (disons 6-8 pages) par équipe suffira. J'aimerais l'avoir le 22 février du fait que c'est probablement déjà pensé et fait et que ça peut demeurer succinct.

Livrable 01

Voici les consignes du livrable L01. Les éléments demandés sont des éléments d'équipe, sauf pour une exception indiquée clairement plus bas :

Un document bref suffira pour chaque équipe, disons 6-8 pages pour le volet équipe et quelques pages par personne pour le volet personnel. Pour la date et pour le mode de livraison, je vous suggère ceci :

Ça vous va? Sinon, faites-moi signe...

Attentes dans le projet de session en lien avec ce cours

Le cours INF739 couvre plusieurs sujets quelque peu disparates. Sachant cela, pour rencontrer les attentes de ce cours, votre projet de session devra lui aussi rencontrer quelques attentes éparses :

Les consignes des livrables vont plus en détail; n'hésitez pas à communiquer avec moi si vous souhaitez des clarifications.

Exemples de code

Ce qui suit vous est gracieusement offert dans le but de vous épargner une recopie pénible d'exemples et de tests proposés dans les notes de cours.

Sources des exemples du document CPA – Volume 00

Cliquez sur cette cible pour obtenir le code de la chaîne pascal simplifiée

Cliquez sur cette cible pour obtenir le code de la chaîne pascal avec itérateurs

Cliquez sur cette cible pour obtenir le code du test 0.0

Cliquez sur cette cible pour obtenir le code du test 0.0b

Cliquez sur cette cible pour obtenir le code du test 0.1

Cliquez sur cette cible pour obtenir le code du test 1.0

Cliquez sur cette cible pour obtenir le code du test 1.1

Cliquez sur cette cible pour obtenir le code du test 1.2

Cliquez sur cette cible pour obtenir le code du test 1.3

Cliquez sur cette cible pour obtenir le code du test 2.0

Cliquez sur cette cible pour obtenir le code du test 2.1

Cliquez sur cette cible pour obtenir le code du test 2.2

Cliquez sur cette cible pour obtenir le code du test 3.0

Sources (pas à jour; prudence!) des exemples du document CPA – Volume 01

Cliquez sur cette cible pour obtenir le code du cas 0

Cliquez sur cette cible pour obtenir le code du cas 1

Cliquez sur cette cible pour obtenir le code du cas 2

Cliquez sur cette cible pour obtenir le code du cas 3

Cliquez sur cette cible pour obtenir le code du cas 4

Sources de projets utilisant des sockets

Cliquez ici pour le projet contenant le code du client multiprogrammé de conversation, format « vanille ».

Cliquez ici pour le projet contenant le code du serveur multiprogrammé conversation « vanille ».

Cliquez ici pour le projet contenant le code du client multiprogrammé de conversation, format « objets autonomes ».

Cliquez ici pour le projet contenant le code du serveur multiprogrammé conversation « objets autonomes ».

Sources de divers exemples qui doivent être retouchés à la lueur de C++ 11

Cliquez sur cette cible pour obtenir le code source de la classe pattern_iterator, document CPA – Volume 02 (ou encore cet article).

Cliquez sur cette cible pour obtenir le code à optimiser pour EX00, série 04, document CPA – Volume 03.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 00, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 01, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 02, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 03, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 04, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 05, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet de l'automate déterministe à états finis, version 06, tel qu'il apparaît dans le document CPA – Volume 04.

Cliquez sur cette cible pour obtenir le code complet du sélecteur de conversions, tel qu'il apparaît dans le document CPA – Volume 04.

Documents sous forme électronique

Cliquez sur cette cible pour aller au document portant sur les classes imbriquées.

Cliquez sur cette cible pour aller au document portant sur les templates.

Cliquez sur cette cible pour aller au document portant sur les singletons.

Cliquez sur cette cible pour aller au document portant sur les mutex portables .

Cliquez sur cette cible pour aller au document portant sur les autoverrous.

Cliquez sur cette cible pour aller au document portant sur les objets autonomes.

Cliquez sur cette cible pour aller au document portant sur les méthodes volatiles.

Cliquez sur cette cible pour aller au document portant sur la conversion automatique entre référentiels.

De manière plus générale, je vous suggère les sections Développement, Questions diverses de C++ et Trucs scouts de h-deb


Valid XHTML 1.0 Transitional

CSS Valide !