Molti dettagli sono dipendenti dall'implementazione, in questo caso lo sviluppo é stato fatto su Cygwin.
Disegnamo una classe, CountDown, che permette di fare il conto alla rovescia.
Dal main vediamo come viene usata, si istanzia un oggetto della classe e si chiama su di esso il metodo run():
CountDown cd1("two x two", 2, 2);
// ...
cd1.run();
Notiamo che tra i membri della classe abbiamo messo un oggetto di tipo pthread_t che rappresenta l'identificatore del thread in cui viene eseguita:
pthread_t m_thread_id;
Il metodo run() crea un nuovo thread salvando nella variabile membro m_thread_id l'identificatore del thread creato e passando l'indirizzo della metodo privato go() che cura i dettagli implementativi della classe.
pthread_create(&m_thread_id, NULL, &go, this)
Il metodo go() é dichiarato static per ragioni di compatibilità con pthread, che é una libreria C e quindi nulla sa di classi e oggetti.
La prima cosa che facciamo in go() é rendere disponibile l'accesso alla classe su cui stiamo lavorando. Il "trucco" a cui abbiamo fatto ricorso é quello di passare this dalla run() via pthread_create come puntatore a void, e qui farlo tornare un puntatore a CountDown con un (piuttosto brutale) static_cast.
CountDown* cd = static_cast(ptr);
E quindi viene eseguito in count down usando i settaggi per l'oggetto corrente. Notiamo l'uso della funzione sleep() per scandire il tempo:
sleep(cd->m_sleep);
Per evitare che un oggetto venga distrutto quando il suo thread é ancora in corso di esecuzione, facciamo una join (ovvero, attendiamo la terminazione del thread) nel distruttore:
pthread_join(m_thread_id, 0);
E questo é, più o meno, tutto. A seguire il codice completo:
#include <string>
#include <iostream>
#include <unistd.h>
#include <errno.h>
#include <sstream>
using namespace std;
class CountDown {
public:
CountDown(const char* id, int start, int sleep =1) :
m_id(id), m_start(start), m_sleep(sleep), m_thread_id(0) {}
~CountDown();
void run();
private:
static void* go(void*);
string m_id;
int m_start;
int m_sleep;
pthread_t m_thread_id;
};
// ensure the object is destroyed only when the thread is terminated
CountDown::~CountDown() {
pthread_join(m_thread_id, 0);
cout << "Dtor completed on " << m_id << endl;
}
// notice: should be static for pthread requirements
void* CountDown::go(void* ptr) {
CountDown* cd = static_cast<CountDown*>(ptr);
ostringstream os;
os << "running " << cd->m_id << endl;
cout << os.str();
for(int i = cd->m_start; i > 0; --i) {
os.str("");
os << cd->m_id << " " << i << endl;
cout << os.str();
sleep(cd->m_sleep);
}
cout << "count down done for " << cd->m_id << endl;
return 0;
}
void CountDown::run() {
if(pthread_create(&m_thread_id, NULL, &go, this) < 0) {
cout << "Error creating thread " << errno << endl;
return;
}
ostringstream os;
os << "Thread id " << m_thread_id << " created (" << m_id << ")" << endl;
cout << os.str();
}
/*
*
*/
int main(int argc, char** argv) {
CountDown cd1("two x two", 2, 2);
CountDown cd2("three", 3);
CountDown cd3("four", 4);
cd1.run();
cd2.run();
cd3.run();
ostringstream os;
os << "All threads are running" << endl;
cout << os.str();
}
Nessun commento:
Posta un commento