Multithread générique

Multithread générique - C++ - Programmation

Marsh Posté le 04-06-2011 à 10:47:57    

Salut à tous,
 
Voici mon problème : j'ai des conteneurs 3D dans lesquels je stocke des données quelconque sur lesquelles je souhaite appliquer divers filtres, morphologies mathématiques, etc... Donc jusqu'ici, pour paralléliser ces opérations, je faisais une fonction pour l'opération elle-même et une fonction qui s'occupait de créer mes threads et de leur répartir le travail (chaque thread traite une partie du volume). Le truc c'est cette seconde fonction est en fait tout le temps la même à l'exception du nom de la fonction que celle-ci appelle et des paramètres de la fonction appelée. Je cherche donc un moyen d'écrire une fonction générique qui pourrait m'appeler n'importe qu'elle fonction. Donc jusqu'ici je suis parvenu à appeler une fonction quelconque en passant un pointeur sur fonction à ma fonction générique mais le hic c'est que toutes les fonctions qu'elle peut potentiellement appeler doivent avoir les mêmes paramètres (ce qui n'est évidemment pas le cas de mes fonctions). J'ai solutionné le problème en passant à mes fonctions un vector de pointeurs. Ça marche alors très bien mais je suis obligé de faire plein de static_cast au début de mes fonctions pour utiliser mes pointeurs et en plus je me retrouve à manipuler des pointeurs partout et c'est un peu ch***t .... Je cherche donc un moyen plus joli de faire ça, qui m'éviterai de passer par un vector de pointeurs :)
Pour la partie threads, j'utilise Boost::threads.
 
 
Merci d'avance :)
 
PS : Voici le code actuel (faites pas attention aux fonctions Run,affiche_test et test_thread:
 

Code :
  1. #include "Mes_Fonctions.hpp"
  2. #ifndef threadbool
  3. #define threadbool 0
  4. #ifdef THREAD
  5. #include <boost/thread/thread.hpp>
  6. #undef threadbool
  7. #define threadbool 1
  8. #endif
  9. #endif
  10. using namespace std;
  11. // ===================================================================
  12. class erode_class{
  13. public:
  14. erode_class(vector<void*> args_):ptrs_(args_){};
  15. void Run(vector<void* > &truc){
  16. cout<<"Paramètres :"<<endl;
  17. for(size_t i=0;i<ptrs_.size();++i){
  18.  cout<<"\t"<<*(static_cast<int *> (ptrs_[i]))<<endl;
  19.  }
  20. cout<<"Paramètre additionel :"<<endl;
  21. for(size_t i=0;i<truc.size();++i){
  22.  int *temp=static_cast<int *> (truc[i]);
  23.  cout<<"\t"<<(*temp)<<endl;
  24.  }
  25.  cout<<endl<<endl;
  26. };
  27. template<class T>
  28. void thread_erode_b(vector<void *> &arguments_,vector<bool> &traites){
  29. if(arguments_.size()!=5){cout<<"Erode arguments are incorrect"<<endl<<"End program"<<endl;exit(0);}
  30. T *volume=static_cast<T *> (arguments_[0]);
  31. T *volume2=static_cast<T *> (arguments_[1]);
  32. int ordre=*(static_cast<int *> (arguments_[2]));
  33. int planstart=*(static_cast<int *> (arguments_[3]));
  34. int planstop=*(static_cast<int *> (arguments_[4]));
  35. const int dim1=(*volume).dim1(),dim2=(*volume).dim2(),dim3=(*volume).dim3();
  36. // Traitement proprement dit
  37. }
  38. private:
  39. vector<void*> ptrs_;
  40. };
  41. typedef void (erode_class::*traitement)(vector<void *> &arguments_,vector<bool> &traites);
  42. typedef void (erode_class::*Run_test)(vector<void *> &truc);
  43. // =========================================================================
  44. template <class T>
  45. void GenericThreadedFunction_2Volumes(T &volume1,T &volume2,const size_t nb_threads,vector<void* > &args,erode_class &test,int &planstart,int &planstop,vector<bool> &traites, traitement fonction){
  46. volume2.resize(volume1.dim1(),volume1.dim2(),volume1.dim3());
  47. #if threadbool
  48. boost::thread_group threads1;
  49. size_t box_size=volume1.dim1();
  50. for (std::size_t n=0; n<nb_threads; ++n){
  51. size_t nb_plans=(int)((double)box_size/(double)nb_threads);
  52. if(n<box_size%nb_threads)nb_plans++;
  53. if(n>=box_size%nb_threads){
  54.  planstart=n*nb_plans+box_size%nb_threads;
  55.  }
  56. else {
  57.  planstart=n*nb_plans;
  58.  }
  59. planstop=planstart-1+nb_plans;
  60. // Ici je sais que ce n'est pas la meilleure façon de répartir les taches mais j'optimiserai ça plus tard :-P
  61. args[3]=&planstart;
  62. args[4]=&planstop;
  63. cout<<n<<" : "<<*(static_cast<int*> (args[3]))<<" to "<<*(static_cast<int*> (args[4]))<<endl;
  64. threads1.create_thread(boost::bind(fonction,boost::ref(test),boost::ref(args),boost::ref(traites)));
  65. }
  66. threads1.join_all();
  67. #else
  68. size_t planstart=0,planstop=volume1.dim1()-1;
  69. fonction(volume1,volume2,ordre,planstart,planstop);
  70. #endif
  71. }
  72. template<typename T>
  73. void affiche_test(double i){
  74. cout<<"Affiche_test = "<<T(i)<<endl;
  75. }
  76. template<typename T>
  77. void test_thread(T j,void (*f)(T k)){
  78. boost::thread_group threads1;
  79. for(int i=0;i<2;++i){
  80. threads1.create_thread(boost::bind(f,j));
  81. sleep(1);}
  82. threads1.join_all();
  83. }
  84. int main(int argc, char *argv[])
  85. {
  86. size_t nb_threads;
  87. #if threadbool
  88. nb_threads=boost::thread::hardware_concurrency();
  89. #else
  90. nb_threads=1;
  91. #endif
  92. slip::RegularVector3dField3d<double> volume1b;
  93. read_slip_data(volume1b,"volume_lif_00005.abe" );
  94. slip::Volume<double> volume1(volume1b.dim1(),volume1b.dim2(),volume1b.dim3()),volume2;
  95. slip::RegularVector3dField3d<double>::const_iterator iter1=volume1b.begin();
  96. slip::Volume<double>::iterator iter2=volume1.begin();
  97. for( ;
  98. iter1!=volume1b.end()&&
  99. iter2!=volume1.end();
  100. ++iter1,++iter2)
  101. (*iter2)=(*iter1)[0];
  102. vector<void*> args,tmp;
  103. erode_class test(args);
  104. int planstart=0,planstop=(int)volume1.dim1(),ordre=3;
  105. // Création du vector de poiteurs sur les paramètres ... ce que je voudrai éviter
  106. tmp.push_back(&volume1);
  107. tmp.push_back(&volume2);
  108. tmp.push_back(&ordre);
  109. tmp.push_back(&planstart);
  110. tmp.push_back(&planstop);
  111. vector<bool> traites(volume1.dim1());
  112. traitement f = &erode_class::thread_erode_b<slip::Volume<double> >;
  113. GenericThreadedFunction_2Volumes(volume1,volume2,nb_threads,tmp,test,planstart,planstop,traites,f);
  114. return 0;
  115. }

Reply

Marsh Posté le 04-06-2011 à 10:47:57   

Reply

Marsh Posté le 04-06-2011 à 17:55:24    

Ça y est, j'ai trouvé une manière faire proche de ce que j'imaginai.
Je crée des classes contenant ma fonction et ses paramètres puis j'ai juste à balancer la fonction dans un thread.
Donc au lieu d'avoir une fonction par traitement j'ai maintenant une classe mais ça ne change pas grand chose :)
 
Merci quand même !  :jap:  
A+  :hello:  
 
 
Le code pour ceux que ça intéresserait :
 

Code :
  1. #include "Mes_Fonctions.hpp"
  2. #ifndef threadbool
  3. #define threadbool 0
  4. #ifdef THREAD
  5. #include <boost/thread/thread.hpp>
  6. #undef threadbool
  7. #define threadbool 1
  8. #endif
  9. #endif
  10. using namespace std;
  11. #if threadbool
  12. boost::mutex mutexTraitement;
  13. #endif
  14. int next_plane(vector<bool> &indices,int k){
  15. for(int i=k+1;i<(int)indices.size();++i){
  16. if(!indices[i])return i;
  17. }
  18. for(int i=k-1;i>0;--i){
  19. if(!indices[i])return i;
  20. }
  21. return -10;
  22. }
  23. // ===================================================================
  24. template<class T>
  25. class erode_class{
  26. public:
  27. erode_class(T &vol1,T &vol2, int ord,int plan1):volume(vol1),volume2(vol2),ordre(ord),planstart(plan1){};
  28. void treatment(vector<bool> &indices){
  29. int k=next_plane(indices,planstart);
  30. const int dim1=volume.dim1(),dim2=volume.dim2(),dim3=volume.dim3();
  31. // Traitements ...
  32. }
  33. private:
  34. T &volume;
  35. T &volume2;
  36. int ordre;
  37. int planstart;
  38. };
  39. // =========================================================================
  40. template <class T,class TT>
  41. void GenericThreadedFunction_2Volumes(T &volume1,T &volume2,const size_t nb_threads,TT &Treatment_Type,int &planstart,vector<bool> &indices){
  42. volume2.resize(volume1.dim1(),volume1.dim2(),volume1.dim3());
  43. #if threadbool
  44. boost::thread_group threads1;
  45. size_t box_size=volume1.dim1();
  46. for (std::size_t n=0; n<nb_threads; ++n){
  47. size_t nb_plans=(int)((double)box_size/(double)nb_threads);
  48. if(n<box_size%nb_threads)nb_plans++;
  49. if(n>=box_size%nb_threads){
  50.  planstart=n*nb_plans+box_size%nb_threads;
  51.  }
  52. else {
  53.  planstart=n*nb_plans;
  54.  }
  55. threads1.create_thread(boost::bind(&TT::treatment,boost::ref(Treatment_Type),boost::ref(indices)));
  56. }
  57. threads1.join_all();
  58. #else
  59. planstart=0;
  60. Treatment_Type.treatment(indices);
  61. #endif
  62. }
  63. int main(int argc, char *argv[])
  64. {
  65. size_t nb_threads;
  66. #if threadbool
  67. nb_threads=boost::thread::hardware_concurrency();
  68. #else
  69. nb_threads=1;
  70. #endif
  71. slip::RegularVector3dField3d<double> volume1b;
  72. read_slip_data(volume1b,"volume_lif_00005.abe" );
  73. slip::Volume<double> volume1(volume1b.dim1(),volume1b.dim2(),volume1b.dim3()),volume2;
  74. slip::RegularVector3dField3d<double>::const_iterator iter1=volume1b.begin();
  75. slip::Volume<double>::iterator iter2=volume1.begin();
  76. for( ;
  77. iter1!=volume1b.end()&&
  78. iter2!=volume1.end();
  79. ++iter1,++iter2)
  80. (*iter2)=(*iter1)[0];
  81. int planstart=0,ordre=3;
  82. vector<bool> indices(volume1.dim1());
  83. erode_class<slip::Volume<double> > erosion1(volume1,volume2,ordre,planstart);
  84. GenericThreadedFunction_2Volumes(volume1,volume2,nb_threads,erosion1,planstart,indices);
  85. return 0;
  86. }

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed