Newsgroup: it.comp.programmare.win32
Titolo: TerminateThread

Esiste un metodo alternativo per chiudere in modo pulito un thread da
parte di un'altro thread?

 parte di un'altro thread?
lo devi realizzare tu con eventi o messaggi.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 parte di un'altro thread?
TerminateProcess della libreria "kernel32"
-- 
IBM: Install Bigger Memory
News 2002 [v 2.07] / StopDialer / PopDuster - 
http://www.socket2000.com
Akapulce portal: 
http://www.akapulce.net

 TerminateProcess della libreria "kernel32"
1) non è "pulito"
2) non termina un solo thread
3) non termina solo i thread
:P


 parte di un'altro thread?
TerminateThread non e' pulito, devi essere tu a "convincere" il tuo 
thread a terminarsi da solo per considerare la sua uscita veramente pulita.
Io di solito lo faccio con un paio di bool. Uno mi serve a dire al 
thread che e' ora di uscire, l'altro e' settato dal thread come ultima 
istruzione e mi serve a segnalare l'avvenuta "morte" :)

 1) non č "pulito"
Diciamo che č piů pulito di TerminateThread nel senso che, ammazzando 
il processo, non dovresti lasciare risorse allocate :)
-- 
Valter Minute
(the reply address of this message is invalid)
(l'indirizzo di reply di questo messaggio non č valido)

Blade <h...@hun.kom> wrote in
news:44cea8c2$0$47974$
4faf...@reader3.news.tin.it
: 

Se usi il booleano devi dichiararlo volatile, altrimenti rischi che 
il thread non si accorga del cambio di valore.
Inoltre un booleano deve essere pollato continuamente per garantire 
la chiusura immediata o comunque rapida del thread.
Un sistema più pulito è quello di usare un evento di sistema che:
- può essere "pollato" usando una WaitForSingle object con timeout a 
0
- può essere usato per sbloccare il thread anche quando questo è in 
wait su altri oggetti (cosa impossibile con il booleano)
Se il thread ha un loop dei messaggi, invece, può essere necessario 
postare un messaggio di quit usando PostThreadMessage.
Inoltre è buona pratica, una volta settato l'evento, attendere che il 
thread si sia completato (magari con un timeout di qualche secondo). 
Questo consentirà al thread di terminare eventuali connessioni verso 
l'esterno, chiudere file aperti etc. 
Queste non sono operazioni indispensabili poichè il sistema operativo 
terminerà le connessioni e chiuderà i file alla terminazione del 
processo, ma può essere utile farlo, ad esempio, per essere sicuri 
che tutti i dati siano stati effettivamente salvati nel file (cosa 
non garantita in caso di chiusura da parte del S.O.) o per comunicare 
a un eventuale client/server remoto il motivo della chiusura della 
connessione.
-- 
Valter Minute
(the reply address of this message is invalid)
(l'indirizzo di reply di questo messaggio non è valido)

connessione.
non sono troppo esperto nella programmazione dei thread in windows. ho
fatto un programma per linux ed ho utilizzato la comodissima funzione:
pthread_cancel() che elimina il thread passato come parametro in modo
pulito
vediamo se ho capito bene, ho dato un'occhiata alle API e penso di
procedere in questo modo:
1. il thread padre invia un messaggio ai thread figli, ordinandogli di
uscire tramite PostThreadMessage(WM_QUIT) oppure PostQuitMessage()
2. il thread figlio (ha magari è in attesa su una recv oppure sulla
select) ritorna con un errore (o comunque gli viene segnalato il
messaggio)
3. il thread padre intanto è in attesa con WaitForSingleObject
4. il thread figlio accortosi del messaggio di uscita, esce
5. il thread padre si sblocca dalla WaitForSingleObject e può uscire
anche lui

 [...]
no, se il "thread figlio" è bloccato su una recv o su una select è inutile
mandare messagi; i messaggi li può ricevere soltanto un thread dotato di
loop dei messaggi (vedi le API GetMessage e DispatchMessage).
se un thread è bloccato su una funzione dei Windows Sockets puoi
risvegliarlo solo con un'APC.
il problema dei Windows Sockets è che per "compatibilità" (o se vogliamo
darle un nome più preciso, per facilità di porting) seguono il design di
quegli obbrobbri dei socket di Berkeley che sono vecchi di qualche
decennio; e come tante altre porcate di funzioni che si vedono negli Unix
(tipo funzioni standard del C come scanf e compagnia) non prevedono
caratteristiche importanti.
nel caso della famiglia di scanf è la dimensione del buffer, nel caso dei
sockets invece ho perso il conto (alerts? overlapped IO? considera che
recv si traduce in qualcosa di simile a ReadFile).
a meno che non sei disposto a cambiare design usando una finestra
invisibile per ricevere le notifiche del socket (cosa che ti permetterebbe
di ricevere anche WM_QUIT), per terminare quel thread ti consiglio di
terminarlo brutalmente con TerminateThread e *successivamente* deallocare
le risorse che ha allocato (come il socket descriptor).
PS: in Win32 non esiste il concetto di thread padre o figlio; le relazioni
di parentela sono inutili nel multithreading.


 il processo, non dovresti lasciare risorse allocate :)
non sempre: gli handles User e GDI rimangono, e in generale tutte le
risorse di "livello globale"; potrebbe anche trattarsi di files o chiavi
di registro che l'applicazione avrebbe dovuto cancellare in uscita.


 decennio;
Dev'essere per questo che si sono inventati il CAsyncSocket: la 
Microsoft non poteva tollerare che qualcuno producesse un'api peggiore 
delle sue :)

 relazioni di parentela sono inutili nel multithreading.
Giustissima osservazione. L'unico thread particolare è il thread 
principale del processo che, terminando, causa la terminazione del 
processo stesso e quindi la morte di tutti gli altri threads.


chiudendo il socket.
mi basta chiudere il socket con il thread del main e controllare i
valori di ritorno di recv o select? quindi se il valore di ritorno
dice che è un socket non aperto, allora il thread esce, liberando le
risorse in modo pulito?
ho anche un'altra domanda: ma in windows come si possono inizializzare
i thread ad uno stato simile a "detached" in linux?

 i thread ad uno stato simile a "detached" in linux?
non conosco, cos'è un thread detached?


 chiudendo il socket.
Io si' e funziona. Ma non solo: e' esattamente quanto previsto nello 
standard originale.

 standard originale.
O__o'
con gli handle non funziona...


 con gli handle non funziona...
Se usi semplicemente le funzioni originali dei socket di Berkley con uno 
shutdown ed un closesocket termini tutte le operazioni pendenti nel modo 
piu' pulito possibile. E' scritto chiaramente (per una volta!) anche su 
MSDN. Forse mi sono perso qualcosa?

 le risorse in modo pulito?
Se hai notato ho iniziato la frase con un "forse" :)


 con gli handle non funziona...
Con che handle?
Se hai un oggetto di sincronizzazione (evento, mutex, thread) su cui un 
thread è in attesa chiudendolo con CloseHandle la funzione di wait 
ritorna con un errore di oggetto non valido, AFAIK.


 parte di un'altro thread?
Io faccio come segue.
Creo due oggetti kernel di tipo "Event", uno chiamiamolo 
"ThreadDaTerminare" e l'altro "ThreadTerminato", entrambi inizialmente 
non segnalati.
Il thread principale, quando vuole terminare il thread di lavoro, 
segnala l'evento "ThreadDaTerminare", e si pone in attesa infinita (con 
WaitForSingleObject) sull'evento "ThreadTerminato".
Il thread di lavoro esegue un loop ad ogni iterazione del quale esegue 
una porzione del proprio lavoro. La condizione di uscita dal loop e' la 
chiamata alla funzione WaitForMultipleObjects, con cui attende che ci 
sia del lavoro da fare o che sia segnalato l'evento "ThreadDaTerminare".
Se il thread si risveglia perche' c'e' del lavoro da fare, allora esegue 
l'iterazione e torna in attesa.
Se invece si risveglia perche' e' segnalato l'evento 
"ThreadDaTerminare", allora segnala l'evento "ThreadTerminato" ed esce.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

non conosco, cos'è un thread detached?
in linux un thread impostato come "detached" libera le risorse al
momento della sua conclusione mentre un thread con impostazioni di
default (thread "joinable") al momento della sua conclusione le
mantiene per consentire ad un altro thread di effettuare un join con
pthread_join, ovvero aspettare la sua conclusione. Al momento del join
rilascerà le risorse.
Un thread del primo tipo quindi, rilascerà le risorse alla sua
conclusione, un thread del secondo tipo deve essere distrutto (con
pthread_cancel, simile a TerminateThread ma "pulito") oppure catturato
con pthread_join, simile credo a WaitForSingleObject.

 non segnalati.
Mi correggo.
L'uso dei due eventi e' indicato in altri casi, piu' generali, ma per il 
caso in cui il thread termina, si puo' evitare di usare l'evento 
"ThreadTerminato".
Il thread principale, quando vuole terminare il thread di lavoro, 
segnala l'evento "ThreadDaTerminare", e si pone in attesa infinita (con 
WaitForSingleObject) sull'handle del thread di lavoro. Infatti, quando 
un thread termina l'handle di tale thread viene segnalato e i thread in 
attesa su tale handle si risvegliano.


Il giorno Tue, 01 Aug 2006 17:46:18 +0200, Blade <h...@hun.kom>
scrisse:

Ma la chiamata closesocket può fallire con il valore WSAEINPROGRESS se
il thread che vogliamo terminare è in una chiamata bloccante (per
esempio select). In tal caso il socket rimane aperto e la chiamata
bloccante non restituisce il codice di errore che desidero per
costringere alla terminazione il thread... o mi sbaglio?

attesa su tale handle si risvegliano.
Il problema è che il thread da terminare è in attesa su "select", c'è
modo di registrare tale evento a select, cosicché al momento della
segnalazione dell'evento da parte del thread chiamante, il thread
chiamato termina?

 esempio select).
Questo e' quanto leggo su MSDN:
"The closesocket function closes a socket. Use it to release the socket 
descriptor s so that further references to s fail with the error 
WSAENOTSOCK. If this is the last reference to an underlying socket, the 
associated naming information and queued data are discarded. Any pending 
blocking, asynchronous calls issued by any thread in this process are 
canceled without posting any notification messages."
D'altra parte tra i possibili errori e' scritto anche questo:
"WSAEINPROGRESS 	A blocking Windows Sockets 1.1 call is in progress, or 
the service provider is still processing a callback function."
Pero' poi non se ne fa piu' menzione ed inoltre non ho idea di cosa 
siano i Winsock 1.1. Ti assicuro pero' che io questa feature la uso a 
nastro per sbloccare i thread bloccati su "recv" o "accept" e non mi ha 
mai dato un problema.

mai dato un problema.
forse i socket creati con la versione 1.1.
a questo punto utilizzo la socketclose controllo che la select esce
con WSAENOTSOCK


Non ho mai programmato seriamente con i socket, ma mi pare che la 
chiamata di sistema "select", come tutte quelle che iniziano con una 
lettera minuscola, sono tipiche di Posix (Unix, Linux, ecc.).
Le chiamate di sistema di Windows iniziano tutte con una lettera 
maiuscola. Le chiamate Posix sono implementate per compatibilita'.
la WaitForMultipleObjects non puo' attendere su un socket.
Esistono le chiamate di sistema WSAEventSelect, 
WSAWaitForMultipleEvents, WSAResetEvent, WSASetEvent, che forse 
soddisfano questa esigenza.


 è una contraddizione
Direi che non e' una novita' per MSDN.
Ma in fondo, forse, non e' neppure un problema di documentazione, ma di 
un'api cosi' incasinata che documentarla per bene e' impossibile :)

 con pthread_join, simile credo a WaitForSingleObject.
in Win32 non c'è nulla del genere: l'unica risorsa visibile ad un
programma che viene liberata automaticamente all'uscita di un thread è il
TLS (Thread Local Storage), cioè lo spazio dedicato ai dati specifici del
thread dove puoi mettere variabili che in runtime verranno replicate
"per-thread"; il compilatore Microsoft supporta il TLS con la direttiva
__declspec(thread)


 MSDN. Forse mi sono perso qualcosa?
no, in effetti a pensarci bene è possibilissimo, dipende sempre
dall'implementazione del TSP


 un'api cosi' incasinata che documentarla per bene e' impossibile :)
posso solo provare a supporre che l'apparente contraddizione dipenda dal
fatto che la cosa può cambiare da un'implementazione all'altra. ipotesi
(senza pretesa di realismo, è solo per far capire cosa intendo):
- Microsoft crea un'implementazione di livello Transport dove la chiusura
di un socket su cui un thread è bloccato fallisce
- MSDN documenta tale feature con la storia del codice WSAEINPROGRESS
- Microsoft, al fine di aderire meglio allo standard di Berkeley, aggiorna
il suo livello Transport migliorandolo (magari proprio in occasione di
Winsock 2) e aggiungendo la feature di interruzione di una chiamata
bloccante
- MSDN viene aggiornata: viene aggiunta qualche riga nella descrizione di
closesocket, ma si scordano di cancellare la riga che descrive il codice
WSAEINPROGRESS :P
volendo qualcuno di noi lo potrebbe segnalare a MS ^^


 ritorna con un errore di oggetto non valido, AFAIK.
ma quelli non c'entrano perché a quel tipo di oggetti del kernel non è
associato un File Object (non puoi passarli a ReadFile o WriteFile), sono
oggetti di sincronizzazione; inizialmente io pensavo principalmente alle
pipe, ma come ho detto dall'altra parte ripensandoci meglio dipende sempre
dai drivers sottostanti: un driver in risposta ad un IRP_MJ_CLOSE (o
meglio ancora IRP_MJ_CLEANUP) può fare quello che gli pare, può decidere
di flushare tutti gli IRP_MJ_READ o WRITE che ha in coda, può decidere di
cancellarli, o può decidere di tenerli così come sono fallendo
l'IRP_MJ_CLOSE o CLEANUP.
insomma, dipende; il kernel di per se' è estremamente flessibile.


 chiamato termina?
la mia risposta definitiva: si, ma non devi farci affidamento perché la
cosa cambia da una versione all'altra di Windows (mi è testimone
l'incoerenza di MSDN).


 
Nota: Fino a VC++ 6 (non ho provato con il 2005) le variabili 
dichiarate in quel modo funzionavano solo se la dll veniva caricata 
linkando la libreria di export al .exe e non usando LoadLibrary.


l'incoerenza di MSDN).
bene, proprio bene :-)
speriamo che sul computer del professore funzioni! :-)

parte di un'altro thread?
Colgo l'occasione per ringraziarvi per la vostra disponibilità.
A risentirci.

volendo qualcuno di noi lo potrebbe segnalare a MS ^^
mi sembra la spiegazione più logica :-)

__declspec(thread)
i thread in stato detached mi servivano in linux per far partire il
thread e fargli fare un compito specifico (l'upload di un file).
Quindi in windows mi conviene farli partire ed aspettare che
termineranno da soli (come avviene con i thread detached in linux),
tanto un eventuale fallimento di qualche chiamata (chiusura di un
socket o errori nella lettura di un file) porterà alla fine del
thread.
Quindi riassumendo:
- per la conversione a windows dei thread non detached faccio così: il
thread del main gli chiude forzatamente il socket, costringendoli ad
uscire da una chiamata bloccante, e catturando il codice di errore
essi  termineranno
- per la conversione a windows dei thread detached non faccio niente,
comunque essi termineranno (non sono in attesa su select o recv)
E' una buona soluzione?

 E' una buona soluzione?
penso proprio di si a meno che il tuo prof non ricompila il tuo programma
su Windows 3.1 o non lo fa girare su Windows 95 :D
tanto se Microsoft ha fatto una cosa per aderire ad uno standard mi pare
improbabile che torni indietro
