Newsgroup: it.comp.programmare.win32
Titolo: Multi-thread sotto NT

Salve a tutti,
ho questo problema. Mi sono trovato a mettere le mani su un'applicazione
Visual C++ scritta da un altro e che utilizza il multi-threading. Da
specifica l'applicazione deve funzionare indifferentemente sotto Win 98
e sotto Win NT. Chi ha sviluppato l'applicazione ha utilizzato le
funzioni standard del Kernel di Windows per gestire i threads:
CreateThread, Sleep, CreateEvent, WairForSingleObject, SetEvent, etc...
La gestione del multi-threading viene nascosta da uno strato superiore
che lo generalizza come multi-tasking per qualunque sistema operativo e
viene inserita in una libreria dove si trova anche la gestione della
seriale che a sua volta si appoggia al multi-tasking stesso. Questa
libreria viene poi linkata nel progetto.
Dopo la premessa veniamo al problema: l'applicazione funziona senza
alcun problema sotto Win 98, mentre sotto Win NT occupa il 99% del tempo
di CPU, facendo sedere completamente la macchina. Da notare che, chi
aveva sviluppato l'applicazione non aveva mai avuto problemi. Io non ho
fatto altro che importare il progetto originale nel mio ambiente di
sviluppo Visual Studio 6.0, ricompilare i sorgenti che mi hanno lasciato
in eredità, senza alcuna modifica e non funziona.
La cosa strana è che, ricompilando gli stessi sorgenti dalla macchina di
chi li ha sviluppati il problema rimane. Non escludo a priori un
sabotaggio da parte di chi ha sviluppato l'applicazione, visto che si è
licenziato :-)
Andando a vedere nei settings del progetto ho notato che nella Code
Generation, vengono utilizzate le run-time library come Single-Threaded,
ho pensato fosse quello, quindi ho ricompilato sia la LIB che
l'applicativo come Multi-Thread, ma sotto NT mi da sempre lo stesso
problema.
Avete qualche idea?
Ciao Riccardo

>problema.
Questa cosa era comunque sbagliata. Bisogna usare le multithreaded library
altrimenti ci sono grossi problemi ad esempio nell'allocazione della
memoria.
antonio

 l'ho avuto e l'ho risolto solo in questo modo.
Meglio uno Sleep(0) che al termine delle operazioni avverte lo scheduler
che non serve piu' il time slice assegnato al thread e, di conseguenza,
puo' essere utilizzato da altri. Vedi documentazione MSDN e funzione
Sleep() sul MS PSDK.
Ciao.
Il Michett@
--


Sei sicuro che non ci sia qualche costante che, in fase di compilazione, 
imposta una modalità di funzionamento a eventi invece che una in polling 
(che potrebbe occupare il 100% di CPU)? Magari la differente gestione è 
legata (come appare dai tuoi test) alla diversa versione del S.O. 
(controlla se vengono utilizzate le API che controllano la versione del 
S.O.). Tieni inoltre presente che alcune funzioni si comportano in modo 
leggermente diverso tra NT e 9x (generamente le versioni NT controllano 
sempre i parametri e in particolare la dimensione delle struct). Può darsi 
che qualche problema di questo tipo ti porti a ottenere un handle non 
valido che poi, utilizzato come parametro in una 
WaitForSingle/MultipleObject(s), genera un ritorno WAIT_ABANDONED o 
WAIT_FAILED, terminando istantaneamente la wait e dando così luogo 
all'occupazione di CPU (se la wait è in un loop...).
L'occupazione della CPU non è di per se un sintomo di malfunzionamento, se 
non và a interferire con le altre applicazioni (se è cioè generata da un 
thread a bassa priorità). 
La vecchia versione presentava un comportamento diverso?
P.S. la gestione della libreria di Visual C++ poteva essere sbagliata già 
in partenza e il problema non si notava perchè nessun thread in background 
utilizzava la lib suddetta. 
Se passi alla versione multi-threaded, ti consiglio comunque di utilizzare 
_beginthread invece di CreateThread (il valore ritornato dalla _beginthread 
è l'HANDLE del tread stesso e puoi quindi continuare ad utilizzarlo nelle 
varie funzioni di Wait, l'unico problema è che l'handle viene rilasciato 
automaticamente al completamento del thread e quindi un'eventuale funzione 
di wait in attesa sul thread potrebbe tornare WAIT_FAILED, segnalando che 
l'handle (o uno degli handle) è invalido, invece di WAIT_OBJECT0+X.
-- 
Valter Minute
min...@inwind.it
 (the reply address of this message is invalid)


Solo se il ciclo di elaborazione è in un thread ad alta priorità e non 
esegue I/O.
Inserire troppe Sleep potrebbe rallentare il tuo programma e penalizzarlo 
nei casi in cui la CPU fosse a (quasi) sua completa disposizione.
Se si tratta di un thread in "busy-wait" (qualcosa del tipo: "controlla il 
flag->se vale 0 esci dal loop->ricontrolla il flag...) dovresti abbassarne 
la priorità o utilizzare un meccanismo ad eventi.


>la priorità o utilizzare un meccanismo ad eventi.
Non sempre e' fattibile o semplice usare la logica degli eventi, soprattuto
in cicli elaborativi. Meno che mai in programmi gia' finiti.
Il multi threading ti permette, a mio modo di vedere, proprio di
semplificare la scrittura di programmi che non sono solo interfaccia utente.
Nel mio caso si trattava di un pop/smtp/proxy server scritto come
applicazione console e girare tutto in logica eventi sarebbe stato un po'
arduo. Arrivavo da un proxy server scritto con le socket asincrone di MFC
senza multithreading ed ero letteralmente impazzito per farlo funzionare.
Antonio


Per fortuna ho sempre girato alla larga da MFC e derivati.


>Per fortuna ho sempre girato alla larga da MFC e derivati.
Concordo pienamente con te.
Antonio

 credere.
Fare eseguire un worker thread che richiede tutta la CPU a priorita`
normale e` una pessima idea. In questi casi i thread si devono mettere a
priorita` idle, cosi` non daranno nessun fastidio al sistema (come
dimostra il servizio di 
distributed.net
 che ho tenuto in background per
mesi).
---
Bye! Lorenzo Lutti
http://www.geocities.com/cirovampiro/

 Ciao Riccardo
Ciao, ho letto il post iniziale di questo thread, e forse l'inghippo
potrebbe trovarsi nella gestione della seriale. In effetti ho un thread
aperto su questo argomento (vedi "baco di NT in I/O OVERLAPPED").
Probabilmente, visto che il tuo codice è multithr. gestisce la seriale in
overlapped; prova a disabilitare la gestione della porta o  rintraccia le
righe con l'istruzione WaitCommEvent: cerca lì il problema.
In bocca al lupo
Ciao

>mesi).
OK grazie del consiglio ma tu avevi detto che quelli a priorita' normale
non bloccano il sistema, invece lo bloccano eccome.
Antonio

 non bloccano il sistema, invece lo bloccano eccome.
Moi? Ti stai confondendo con qualcun altro. :)
Comunque anche se non l'ho detta sono d'accordo con quell'affermazione:
qui da me (NT4) i processi a priorita` normale che tentano di usare
tutta la CPU rendono il sistema molto piu` *laggato*, come e` giusto che
sia; c'e` una bella differenza fra "laggare" e "bloccare" il sistema. Io
posso lanciare quando voglio il Task Manager (che viene eseguito ad alta
priorita`) e terminare quando voglio il processo birichino.
---
Bye! Lorenzo Lutti
http://antani.virtualave.net/

