Troppe volte ho trovato il modo per risolvere quello che mi chiedi, secondo me sono troppo complicati. Per esempio devi definire nuovi tipi di classi, librerie di link ecc. Quindi ho deciso di scrivere alcune righe di codice che permettano all'utente finale di essere fondamentalmente in grado di "thread-ize" un "void :: method (void)" qualunque classe. Sicuramente questa soluzione che ho implementato può essere estesa, migliorata ecc., Quindi, se hai bisogno di metodi o funzionalità più specifici, aggiungili e sii così gentile da tenermi aggiornato.
Ecco 3 file che mostrano cosa ho fatto.
#ifndef MUTEXCONDITION_H_
#define MUTEXCONDITION_H_
#include <pthread.h>
#include <stdio.h>
class MutexCondition
{
private:
bool init() {
pthread_mutex_init(&m_mut, NULL);
pthread_cond_init(&m_con, NULL);
return true;
}
bool destroy() {
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&m_con);
return true;
}
public:
pthread_mutex_t m_mut;
pthread_cond_t m_con;
MutexCondition() {
init();
}
virtual ~MutexCondition() {
destroy();
}
bool lock() {
pthread_mutex_lock(&m_mut);
return true;
}
bool unlock() {
pthread_mutex_unlock(&m_mut);
return true;
}
bool wait() {
lock();
pthread_cond_wait(&m_con, &m_mut);
unlock();
return true;
}
bool signal() {
pthread_cond_signal(&m_con);
return true;
}
};
#endif
// La classe che incapsula tutto il lavoro per il thread-ize di un metodo (test.h):
#ifndef __THREAD_HANDLER___
#define __THREAD_HANDLER___
#include <pthread.h>
#include <vector>
#include <iostream>
#include "Mutex.h"
using namespace std;
template <class T>
class CThreadInfo
{
public:
typedef void (T::*MHT_PTR) (void);
vector<MHT_PTR> _threaded_methods;
vector<bool> _status_flags;
T *_data;
MutexCondition _mutex;
int _idx;
bool _status;
CThreadInfo(T* p1):_data(p1), _idx(0) {}
void setThreadedMethods(vector<MHT_PTR> & pThreadedMethods)
{
_threaded_methods = pThreadedMethods;
_status_flags.resize(_threaded_methods.size(), false);
}
};
template <class T>
class CSThread {
protected:
typedef void (T::*MHT_PTR) (void);
vector<MHT_PTR> _threaded_methods;
vector<string> _thread_labels;
MHT_PTR _stop_f_pt;
vector<T*> _elements;
vector<T*> _performDelete;
vector<CThreadInfo<T>*> _threadlds;
vector<pthread_t*> _threads;
int _totalRunningThreads;
static void * gencker_(void * pArg)
{
CThreadInfo<T>* vArg = (CThreadInfo<T> *) pArg;
vArg->_mutex.lock();
int vIndex = vArg->_idx++;
vArg->_mutex.unlock();
vArg->_status_flags[vIndex]=true;
MHT_PTR mhtCalledOne = vArg->_threaded_methods[vIndex];
(vArg->_data->*mhtCalledOne)();
vArg->_status_flags[vIndex]=false;
return NULL;
}
public:
CSThread ():_stop_f_pt(NULL), _totalRunningThreads(0) {}
~CSThread()
{
for (int i=_threads.size() -1; i >= 0; --i)
pthread_detach(*_threads[i]);
for (int i=_threadlds.size() -1; i >= 0; --i)
delete _threadlds[i];
for (int i=_elements.size() -1; i >= 0; --i)
if (find (_performDelete.begin(), _performDelete.end(), _elements[i]) != _performDelete.end())
delete _elements[i];
}
int runningThreadsCount(void) {return _totalRunningThreads;}
int elementsCount() {return _elements.size();}
void addThread (MHT_PTR p, string pLabel="") { _threaded_methods.push_back(p); _thread_labels.push_back(pLabel);}
void clearThreadedMethods() { _threaded_methods.clear(); }
void getThreadedMethodsCount() { return _threaded_methods.size(); }
void addStopMethod(MHT_PTR p) { _stop_f_pt = p; }
string getStatusStr(unsigned int _elementIndex, unsigned int pMethodIndex)
{
char ch[99];
if (getStatus(_elementIndex, pMethodIndex) == true)
sprintf (ch, "[%s] - TRUE\n", _thread_labels[pMethodIndex].c_str());
else
sprintf (ch, "[%s] - FALSE\n", _thread_labels[pMethodIndex].c_str());
return ch;
}
bool getStatus(unsigned int _elementIndex, unsigned int pMethodIndex)
{
if (_elementIndex > _elements.size()) return false;
return _threadlds[_elementIndex]->_status_flags[pMethodIndex];
}
bool run(unsigned int pIdx)
{
T * myElem = _elements[pIdx];
_threadlds.push_back(new CThreadInfo<T>(myElem));
_threadlds[_threadlds.size()-1]->setThreadedMethods(_threaded_methods);
int vStart = _threads.size();
for (int hhh=0; hhh<_threaded_methods.size(); ++hhh)
_threads.push_back(new pthread_t);
for (int currentCount =0; currentCount < _threaded_methods.size(); ++vStart, ++currentCount)
{
if (pthread_create(_threads[vStart], NULL, gencker_, (void*) _threadlds[_threadlds.size()-1]) != 0)
{
return false;
}
else
{
++_totalRunningThreads;
}
}
return true;
}
bool run()
{
for (int vI = 0; vI < _elements.size(); ++vI)
if (run(vI) == false) return false;
return true;
}
T * addElement(void)
{
int vId=-1;
return addElement(vId);
}
T * addElement(int & pIdx)
{
T * myElem = new T();
_elements.push_back(myElem);
pIdx = _elements.size()-1;
_performDelete.push_back(myElem);
return _elements[pIdx];
}
T * addElement(T *pElem)
{
int vId=-1;
return addElement(pElem, vId);
}
T * addElement(T *pElem, int & pIdx)
{
_elements.push_back(pElem);
pIdx = _elements.size()-1;
return pElem;
}
T * getElement(int pId) { return _elements[pId]; }
void stopThread(int i)
{
if (_stop_f_pt != NULL)
{
( _elements[i]->*_stop_f_pt)() ;
}
pthread_detach(*_threads[i]);
--_totalRunningThreads;
}
void stopAll()
{
if (_stop_f_pt != NULL)
for (int i=0; i<_elements.size(); ++i)
{
( _elements[i]->*_stop_f_pt)() ;
}
_totalRunningThreads=0;
}
};
#endif
// Un file di esempio di utilizzo "test.cc" che su linux ho compilato con La classe che incapsula tutto il lavoro per threadizzare un metodo: g ++ -o mytest.exe test.cc -I. -lpthread -lstdc ++
#include <test.h>
#include <vector>
#include <iostream>
#include <Mutex.h>
using namespace std;
class TPuck
{
public:
bool _go;
TPuck(int pVal):_go(true)
{
Value = pVal;
}
TPuck():_go(true)
{
}
int Value;
int vc;
void setValue(int p){Value = p; }
void super()
{
while (_go)
{
cout <<"super " << vc << endl;
sleep(2);
}
cout <<"end of super " << vc << endl;
}
void vusss()
{
while (_go)
{
cout <<"vusss " << vc << endl;
sleep(2);
}
cout <<"end of vusss " << vc << endl;
}
void fazz()
{
static int vcount =0;
vc = vcount++;
cout <<"Puck create instance: " << vc << endl;
while (_go)
{
cout <<"fazz " << vc << endl;
sleep(2);
}
cout <<"Completed TPuck..fazz instance "<< vc << endl;
}
void stop()
{
_go=false;
cout << endl << "Stopping TPuck...." << vc << endl;
}
};
int main(int argc, char* argv[])
{
int vN = 3;
CSThread<TPuck> PuckThreadMaker;
PuckThreadMaker.addThread(&TPuck::fazz, "fazz1");
PuckThreadMaker.addThread(&TPuck::fazz, "fazz2");
PuckThreadMaker.addThread(&TPuck::fazz, "fazz3");
PuckThreadMaker.addThread(&TPuck::vusss, "vusss");
PuckThreadMaker.addThread(&TPuck::super, "super");
PuckThreadMaker.addStopMethod(&TPuck::stop);
for (int ii=0; ii<vN; ++ii)
{
TPuck * vOne = PuckThreadMaker.addElement();
}
if (PuckThreadMaker.run() == true)
{
cout <<"All running!" << endl;
}
else
{
cout <<"Error: not all threads running!" << endl;
}
sleep(1);
cout <<"Totale threads creati: " << PuckThreadMaker.runningThreadsCount() << endl;
for (unsigned int ii=0; ii<vN; ++ii)
{
unsigned int kk=0;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
}
sleep(2);
PuckThreadMaker.stopAll();
cout <<"\n\nAfter the stop!!!!" << endl;
sleep(2);
for (int ii=0; ii<vN; ++ii)
{
int kk=0;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl;
}
sleep(5);
return 0;
}