Newsgroup: it.comp.os.linux.development
Titolo: uso di pthread in classe C++

Ciao,
ho una bella classe, e nella mia bella classe
faccio uso della libreria pthread, ovviamente
per linux...
Il mio problema č che la pthread_create() vuole
un puntatore ad una funzione che prende un puntatore
void come parametro e restituisce un puntatore void,
in sintesi: void * (*)(void *)
Il punto come avrete intuito e che devo usare come funzione
thread, una funz della classe che ha la forma diversa di:
void * (*TSender::Funzione)(void *) diversa da quella accettata
da pthread_create().
Come risolvo il problema????
Avevo pensato ad una funzione friend della classe che cosě
rispetta il puntatore di cui sopra, ma non mi va di inquinare
l'incapsulamento della classe.
Qualche idea???
Grazie

 Qualche idea???
Invece di una funzione friend, potresti usare un metodo static con la
signature opportuna.
Dal tipo di puntatore che indichi, la "funzione" di cui parli è un
metodo non static (non di classe), che ha senso solo se invocato su
un'istanza della classe in questione, per cui friend o no, devi sapere su
quale istanza invocare quel metodo.
Se la tua classe è un singleton, la soluzione è ovvia: ti fai dare il
puntatore all'istanza dal metodo static opportuno e poi ci invochi sopra
il metodo.
Se la tua classe non è un singleton, potresti 
a) istanziarla :-)
b) passare come secondo argomento a pthread_create() il puntatore
   all'istanza
c) alla funzione friend o al metodo static del caso vien passato
   tale puntatore, fai il downcast al tipo della tua classe
   (credo sia il caso di andare di reintepret_cast<>) e poi ci
   invochi sopra il metodo.
-- 
  |   \    \  | ___|_  |_  |  ianezz a casa sua... :-)
  |  _ \  | \ | _|    /   /   Verba volant, scripta
 _|_/  _\_|  _|____|___|___|  manent, data corrupted

 Come risolvo il problema????
Beh, crei una funzione globale che passi a pthread_create(), e come 
argomento per questa funzione mandi un puntatore a TSender. Dopodichè 
questa funzione globale richiama la tua funzione membro della classe.

 Come risolvo il problema????
Puoi usare delle librerie gia` pronte oppure usare una cosa come questa
(funziona, la sto usando per un progetto :D):
template <typename T, typename R> class Thread {
	private:
		pthread_t tid;
		int state;
		enum {THREAD_FINISHED, THREAD_RUNNING, THREAD_CANCELLED};
		struct arg_t {
			Thread<T, R> *self;
			T args;
		} args;
		R ret_;
		/** Helper function.
		 *
		 * This static function acts as proxy for
		 * pthread_create(). It needs to be static because
		 * pthread_create() can't handle pointer-to-method (ie.
		 * 'this' will be lost).
		 *
		 * @param arg struct arg_t, casted to void *
		 * 
		 * @return Always returns NULL. Return type is void *
		 * for compatibility with pthread_create().
		 */
		static void *thread_helper(void *arg) {
			arg_t *p = reinterpret_cast<arg_t *>(arg);
			p->self->state = THREAD_RUNNING;
			p->self->ret_ = p->self->main(p->args);
			p->self->state = THREAD_FINISHED;
			pthread_exit(NULL);
		};
		/** Main function of the thread.
		 *
		 * This pure virtual function shall be implemented by
		 * subclasses and it's the main function executed by the
		 * thread.
		 */
		virtual R main(T) = 0;
	public:
		Thread(): tid(-1), state(THREAD_FINISHED) { args.self = this; }
		virtual ~Thread() {}
		virtual bool start(T);
		virtual bool join();
		virtual void cancel();
 
		R ret() { return ret_; }
};
template <typename T, typename R> bool Thread<T, R>::start(T a) {
	if (state != THREAD_FINISHED)
		return false;
	args.args = a;
 
	void *p = reinterpret_cast<void *>(&args);
	if (pthread_create(&tid, NULL, thread_helper, p) == 0)
		return true;
	else
		return false;
}
Ometto il resto per evitare allungare troppo il post (se vuoi il file
completo posso mandartelo per email).
La chiave e` la funzione statica thread_helper, che e` quella
effettivamente passata alla pthread_create. La funzione thread_helper
recupera il 'this' (self) per vie traverse (in pratica gli viene
sfruttando in quarto argomento della pthread_create).
Tu devi solo ereditare da questa classe ed implementare il metodo main;
il codice di main puoi scriverlo come se fosse un normale metodo.
Occhio che c'e` una race condition tra il settaggio dello stato nella
funzione helper ed i metodi pubblici (start, join, ecc); per l'uso che
ne faccio io non e` un problema ma potresti voler inserire un lock a
protezione dello stato.
Luca
-- 
Home: 
http://kronoz.cjb.net
Il coraggio non mi manca.
E` la paura che mi frega...

 Grazie
Grazie a tutti, ho risolto con una funzione friend, passando un 
riferimento della classe, alla funzione...

AlterX wrote:
[cut]
Visto che stiamo in tema di thread...
ho un bel problema strano:
i thread sembrano funzionare bene, ma quando provo ad aprire i socket (uno
per ogni thread), viene eseguito tutto, ma all'istruzione:
dominio = gethostbyname("
www.pippo.it
");
si blocca, nel senso che esegui l'istruzione, ma sembra ignorare tutto,
il test, eventuali printf dopo l'istruzione (appunto per vedere se supera
quella istruzione), e termina il programma normalmente...
Come è possibile che non segnala un errore o altro?!?
Ho letto nella guida che gethostbyname restituisce un puntatore a memoria
static, quindi non compatibile con più threads.
Infatti, prima di eseguire i thread in sequenza, ne viene aperto uno che
viene risolto in modo corretto, ma poi...il problema!

 Come è possibile che non segnala un errore o altro?!?
Probabilmente perché non se ne accorge affatto, e nelle aree statiche,
oltre che ai risultati che ti ritorna, magari ci tiene anche dati per il
suo funzionamento interno.
Che succede se una gethostbyname() in un thread viene interrotta a metà,
e ne parte un'altra in un altro thread, che sovrascrive parte delle
informazioni nelle aree statiche, e poi riprende la prima? 
Probabilmente succede un bel casino, visto che la prima riprenderebbe
l'esecuzione con i suoi dati interni parzialmente sovrascritti.
IMHO: o usi la versione rientrante di gethostbyname() della glibc
(gethostbyname_r()), o usi un mutex per serializzare le chiamate a
gethostbyname().


 
Lo stesso comportamento lo ha dato anche con i mutex...questo su una
debian, mentre sulla gentoo di casa, funziona bene!

 
La versione rientrante, mi restituisce un errore: "Resolver internal error"
e sinceramente non so il perchè!

 e sinceramente non so il perchè!
Ok sono riuscito a farla funzionare...con la versione senza thread, 
funziona bene, ma con la versione in thread, stessa cosa: esce quando
esegue l'istruzione gethostbyname_r!!!!