Newsgroup: it.comp.lang.delphi
Titolo: Sincronizzare i threads

Ciao a tutti!
Ho una applicazione costituita da un thread principale e da un thread
secondario, il quale richiama altri threads. Quello che dovrei fare è
attendere che tutti i threads richiamati dal thread secondario
terminino. Sono riuscito a farlo con questo ciclo while:
//Thread secondario
while (!Terminated && stop==false && contatore<totale)
{
    Application->ProcessMessages();
    ::Sleep(100);
}
La variabile contatore la incremento negli altri threads, richiamati
dal secondario, mediante una TCriticalSection.
Il problema è che si genera un Access Violation Error, il quale forse
è causato da un accesso contemporaneo alla variabile contatore: mentre
la variabile è bloccata dalla TCriticalSection per la scrittura in
qualche sottothread, il thread secondario tenta di accedervi in lettura
per fare il confronto "contatore<totale".
Forse dovrei inserire in qualche modo una TCriticalSection anche qui.
Avete qualche idea su come risolvere questo problema?
Grazie!!

 secondario, il quale richiama altri threads. [...]
Sbaglio o tutti i tuoi post fanno riferimento a C++Builder?
Forse dovresti inviare le tue richieste ad un gruppo di discussione 
dedicato a questo linguaggio: avresti più possibilità di ottenere 
risposte, oltre al fatto che qui potrebbe risultare OT perché si parla 
di Delphi, benché basato sulle stesse librerie e componenti.
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

 
In effetti e' vero...
Puo' darsi comunque che questo NG sia un po' piu' vivo, dico "puo' 
darsi" perche' non frequento il newsgroup relativo a BC++Builder e 
quindi lui tenda a cercare delle risposte qui.
D'altro canto e' vero che i due tool si basano sulle stesse librerie, 
quindi gli argomenti sono in comune...
Uhm... Off-topic o non off-topic, bel dilemma :)
Ciao,
baba.

terminino. Sono riuscito a farlo con questo ciclo while:
Io uso WaitForMultipleObjects.
Ti copio e incollo una porzione di un mio servizio.
Senza stare li a spiegare troppo, il concetto č: 
- assegni a PWOHandleArray gli handles dei tuoi thread
- segnali ai thread di terminare
- attendi per un certo periodo che terminino (waitformultipleobjects)
- Kill eventuali thread che per qualche ragione non terminano.
var
  I: Integer;
  WS: Cardinal;
  B: LongBool;
  GroupHandle: PWOHandleArray;
begin
  New(GroupHandle);
  for I := 1 to NumOfThreads do
  begin
    GroupHandle[I - 1] :=TOperationThread(OperationThreads[I]).Handle;
    SetEvent(OperationQuitHandles[I]);
  end;
  WaitForMultipleObjects(NumOfThreads, GroupHandle, True, 60000);
  for I := 1 to NumOfThreads do
  begin
    B :=
GetExitCodeThread(TOperationThread(OperationThreads[I]).Handle, WS);
    if not(B) or (WS = STILL_ACTIVE) then
    begin
      TerminateThread(GroupHandle[I-1], 0);
      EventLog.AddLogInfo(tsWarning, Format('OperationThread #%.2d
KILLED', [I]));
    end;
    TOperationThread(OperationThreads[I]).Free;
  end;
-- 
Ore 18.30: premo invio.

carmelo ha scritto:

Ciao,
   premesso che un problema di programmazione MultiThread e' 
difficilmente comprensibile con quattro righe, mi sembra che il problema 
stia nel fatto che il thread secondario vada a leggere direttamente la 
variabile "contatore".
Corretto che i thread figli la scrivano passando per un metodo che 
prevede l'uso di una TCriticalSection, ora perche' non fai un metodo che 
funzioni con lo stesso pricipio per la lettura?
Solo a titolo d'esempio, perdona i vari errori ma vado di fretta:
---
var
     FLock: TCriticalSection;
implementation
procedure    WriteContatore;
begin
     // questa l'hai gia' fatta
end;
function    ReadContatore: Integer;
begin
     FLock.Aquire;
     try
         Result := contatore;
     finally
         FLock.Release;
     end;
end;
---
Quindi:
---
//Thread secondario
  while (!Terminated && stop==false && ReadContatore()<totale)
  {
      Application->ProcessMessages();
      ::Sleep(100);
  }
end;
---
Ciao,
baba.

 ha scritto nel messaggio 
news:1143017728.1...@z34g2000cwc.googlegroups.com...


variabile "contatore".
L'accesso concorrenziale ad una variabile di quel tipo serve solo in
scrittura, non di certo in lettura.  Non serve vincolare la lettura a
una critical section.

risolverebbero egregiamente anche il tuo problema. 
I mutex sono oggetti kernel che vanno bene per la sincronizzazione tra
processi, ancor prima che tra thread.  Per la sincronizzazione tra
thread č *molto* meglio usare le critical section (che sono oltretutto
molto piů veloci, dato che non richiedono diverse decine di istruzioni
di swap tra user space a kernel space).
p.s.: come bisogna dirtelo che devi "quotare" correttamente?

per fare il confronto "contatore<totale".
Ma de che.  L'accesso in lettura di una variabile come quella non
comporta *alcun* problema, perché è atomico (non è infatti possibile
che venga letta mezza DWORD in un modo e mezza nell'altro), a
prescindere dal fatto che altri thread vi stiano accedendo in
scrittura vincolata.