Cas 0 – application concurrente d'un calcul sur une séquence de nombres

Le cas 0, « application concurrente d'un calcul sur une séquence de nombres », tel que proposé dans vos notes de cours, se présente comme suit.

struct Probleme
{
   virtual bool est_resolu() const volatile = 0;
   virtual void resoudre_un() volatile = 0;
   virtual ~Probleme() throw()
      { }
};
unsigned long __stdcall calcul(void *p)
{
   for (Probleme *prob = static_cast<Probleme *>(p);
        !prob->est_resolu(); )
      prob->resoudre_un();
   return 0UL;
}
#include "Mutex.h"
#include <vector>
using std::vector;
#include <cmath>
using std::sqrt;
class RacinesCarrees
   : public Probleme
{
   typedef vector<double> vdbl;
   vdbl valeurs_;
   vdbl racines_;
   Mutex mutex_;
   void resoudre_un()
   {
      if (racines_.size() != valeurs_.size())
         racines_.push_back
            (sqrt(valeurs_[racines_.size()]));
   }
   bool est_resolu() const
      { return racines_.size() == valeurs_.size(); }
public:
   template <class Itt>
      RacinesCarrees(Itt debut, Itt fin)
         : valeurs_(debut, fin)
      {
      }
   bool est_resolu() const volatile
   {
      Autoverrou av(mutex_);
      return const_cast<const RacinesCarrees*>(this)->est_resolu();
   }
   void resoudre_un() volatile
   {
      Autoverrou av(mutex_);
      const_cast<RacinesCarrees*>(this)->resoudre_un();
   }
   vector<double> resultats() const
      { return racines_; }
};
#include <cstdlib>
using std::srand;
using std::rand;
double GenererValeur() throw ()
   { return static_cast<double>(rand()%1000+1); }
#include <iostream>
#include <ctime>
#include <algorithm>
#include <windows.h>
int main()
{
   using std::begin;
   using std::end;
   using std::cout;
   using std::endl;
   using std::clock;
   using std::clock_t;
   using std::time;
   using std::for_each;
   using std::generate;
   const int N = 1000000;
   vector<double>valeurs(N);
   srand(static_cast<unsigned int>(time(0)));
   generate(valeurs.begin(), valeurs.end(), [](){
      return static_cast<double>(rand()%1000+1);
   });
   const int MAX_THREADS = 10;
   for (int n = 1; n <= MAX_THREADS; ++n)
   {
      RacinesCarrees rc(Valeurs, Valeurs+NB_VALEURS);
      vector<HANDLE>v(n);
      for (int i = 0; i < n; ++i)
         v[i] = CreateThread(0, 0, calcul, &rc, CREATE_SUSPENDED, 0);
      clock_t avant = clock();
      for_each(v.begin(), v.end(), ResumeThread);
      WaitForMultipleObjects(n, &v[0], TRUE, INFINITE);
      clock_t apres = clock();
      for_each(v.begin(), v.end(), CloseHandle);
      cout << "Temps total, " << N << " valeurs, " << n << " thread(s): "
           << static_cast<double>(apres-avant)/
              CLOCKS_PER_SEC * 1000
           << " ms." << endl;
   }
}

Sur mon petit ordinateur portatif, compilé avec Visual Studio 2010, configuration Release, et en prenant bien entendu soin d'ajouter _SECURE_SCL=0 aux options du préprocesseur pour désactiver les (franchement inutiles et nuisibles) Checked Iterators, j'obtiens :

Temps total, 1000000 valeurs, 1 thread(s): 2425 ms.
Temps total, 1000000 valeurs, 2 thread(s): 10082 ms.
Temps total, 1000000 valeurs, 3 thread(s): 11696 ms.
Temps total, 1000000 valeurs, 4 thread(s): 11454 ms.
Temps total, 1000000 valeurs, 5 thread(s): 8826 ms.
Temps total, 1000000 valeurs, 6 thread(s): 9085 ms.
Temps total, 1000000 valeurs, 7 thread(s): 8742 ms.
Temps total, 1000000 valeurs, 8 thread(s): 8513 ms.
Temps total, 1000000 valeurs, 9 thread(s): 10353 ms.
Temps total, 1000000 valeurs, 10 thread(s): 9267 ms.
Appuyez sur une touche pour continuer...

Valid XHTML 1.0 Transitional

CSS Valide !