Newsgroup: it.comp.programmare.win32
Titolo: variabili & threads

Salve a tutti.
ho 2 threads creati con la funzione CreateThread();
in uno di questi 2 c'e' un ciclo del tipo:
x=5;
while(x!=0){};
a prima vista sembrerebbe infinito ed infatti cosi sarebbe senonche l'altro
trhead modifica proprio la variabile
x ponendola a 0.
e' giusta una cosa del genere o dovrei usare un altro metodo????
perche' a volte funziona e a volte no???
diciamo il 50% delle volte che lo eseguo non va e il 50% va.... cosi non
riesco a capire!!!!!! :o(
ah se poi provo a debuggare, mettendo un breakpoint sul while, cosi non va
proprio ma penso che sia
un problema di visual studio che non riesce a debbugare bene i threads o
sbaglio?
Tnks

riesco a capire!!!!!! :o(
race condition... devi lockare su x
cerca su msdn 
Create/Open/ReleaseMutex, 
WaitForSingleObject(Ex), WaitForMultipleObject(Ex),
Initialize/Delete/Enter/LeaveCriticalSection
InterLocked*,
Create/Open/ReleaseSemaphore
sbirish


mmm ti ringrazio, solo un dubbio xo': io avevo letto che la
"sincronizzazione"
e' necessaria solo se tutti e 2 i thread vogliono modificare la variabile,
nel mio caso
invece un thread la modifica, l'altro la legge solamente, inoltre in un
ciclo infinito
quindi l'altro prima o poi la cambia e questo esce dal ciclo, no??
/*I programmatori esperti ben presto apprendono che in molti casi la
sincronizzazione è necessaria soltanto quando si deve modificare l'oggetto
da proteggere. Un thread che desidera unicamente leggere lo stato di un
oggetto non deve impostare un blocco. Questa modalità funziona soltanto se
l'oggetto da esaminare non è una struttura di ampie dimensioni. Nel caso di
un contatore, un thread che desidera verificare se il suo valore è zero può
farlo con un semplice test. Se un altro thread lo ha appena incrementato o
un secondo dopo lo decrementa a zero, non ha alcuna importanza se, al
momento della verifica, il valore è zero o diverso da zero.*/

 wrote in message
news:rpOVa.29909$sj6.6...@tornado.fastwebnet.it...
<cut/>
la sincronizzazione č necessaria se entrambi vogliono accedere in scrittura
alla variabile .. si č vero
cmq, quel che ti conviene fare č dichiarare la variabile col modificatore
volatile, altrimenti al compilatore
potrebbe girare di metterla in un registro, e non accedere alla memoria ad
ogni lettura della variabile...
antonio

[snip]
falso, a meno di non avere la certezza che le operazioni su quel tipo
siano atomiche. 
Se potessi dare per scontato che le operazioni sugli int in windows
siano atomiche, spiegami l'esistenza di questa api:
InterlockedIncrement
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/interlockedincrement.asp
Da dove hai preso questo passo che hai citato?
sbirish.

alla variabile .. si è vero
no, è falso, visto che non è garantito che le operazioni sul tipo
siano atomiche. La sincronizzazione, finché non si ha tale certezza, è
inutile soltanto se sono tutti reader.
sbirish.

 Da dove hai preso questo passo che hai citato?
cercando su google:
http://www.tech.it/twire/mesi/articoli/tw-9805/cd-art02.htm
Grazie ancora del tempo dedicatomi ;o)

 ogni lettura della variabile...
Grazie, ora mi guardo bene il "volatile" cmq penso di aver intuito ;o)
spero poi fungi :oD

 Tnks
Un saluto.
Riccardo.

[SNIP]


Scusa allora per questa affermazione eretica priva di senso :o)
pero' per quel che mi riguarda č vero :oD
cioč: ho 2 thread, lancio il debug e tutti e 2 vengono eseguiti
corretamente,
se invece in questi 2 metto breakpoint, lancio il debug entro nel primo
thread che viene eseguito;
nel frattempo dovrebbe essere partito anche l'altro thread ma
A) mentre io sto schiacciando il mio bellissimo bottoncino F6 per scorrere
il primo thread, non mi fa soffermare
    anche sul breakpoint del thread2,
B) anche mettendo il breakpoint sul solo thread1, sembra che il thread2 non
venga eseguito... questo magari perche' ho sbagliato io
qualcosa nella sincronizzazione, ma a me da quell'impressione, visto che in
modalita' release il tutto funzionava, in modalita debug
a volte si a volte no, mettendo un breakpoint non funzionava piu, o meglio
entrava nel loop infinito e l'altra variabile non veniva mai cambiata.
provero' dopo aver fatto le modifiche di sincronismo.
Grazie ancora.

...

Certo. Estremamente corretto e pulito.
Davo per scontato che nella main ci si ponesse in attessa della fine
dell' elaborazione.
Saluti.

 sbirish.
Esatto.

 >[SNIP]
argh!!! un momento: sono obbligato ad attendere che i 2 thread finiscano???
stò utilizzando tutto cio' in un applicazione client/server, il server
quindi fa partire
un thread per ogni "stringa" ricevuta, se 2 client inviano quasi
contemporaneamente un messaggio,
mettendo la Wait, dovrei aspettare di aver servito il primo client prima di
servire il secondo,
io pensavo di servirli (per quel che e' possibile) parallelamente.

 io pensavo di servirli (per quel che e' possibile) parallelamente.
Devi creare un thread di ricezione nel server.
Esso servira' essenzialmente solo a smistare le chiamate dei vari
client.
Quando un client si connette...all' interno del thread di ricezione
lanci il thread di lavoro ,uno per ogni client( OVVIAMENTE la
ThreadFunzione č LA STESSA per tutti i client), i client a quel punto
verranno processati "parallelamente".
Il metodo piu' opportuno poi per terminare i vari thread di lavoro č
lasciarli uscire dolcemente dalla propria ThreadFunzione una volta
concluso il lavoro.
Il thread di ricezione invece č sempre attivo ed in genere termina
solo al termine dell' applicazione.

 solo al termine dell' applicazione.
si si qua tutto ok :o)

 race condition... devi lockare su x
uh per carità. Race condition? su un intero?
-- 
  < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
      Don't stand, REACT!      version 0.1.2. C, C++ and ASM developers
                               and beta testers are welcome!

 e' giusta una cosa del genere o dovrei usare un altro metodo????
certo che è giusta, se il valore di x non viene usato altrove. E' che x 
è una variabile in memoria condivisa, e quindi va dichiarata "volatile"


uh per carità. Race condition? su un intero?
non mi risulta che su x86 sia garantita l'atomicità sulle operazioni
su int a 32bit, allineato o meno... 
altrimenti..
a cosa servirebbero le Interlocked* sui 32bit allora? 
LOCK? 
/kernel/include/asm-i386/atomic.h ?
perché Atomic_Op in ACE per win32 specializza usando
InterlockedExchangeAdd invece di usare una semplice operazione su un
int?
perché gcc riporta questo bug per x86 se non esistessero le race sugli
int?
<cite from="qualcosa/gcc/faq">
 3.7 Threading is broken on i386
 Support for atomic integer operations is/was broken on i386  
 platforms. The assembly code accidentally used opcodes that are only 
 available on the i486 and later. So if you configured GCC to target, 
 for example, i386-linux, but actually used the programs on an i686, 
 then you would encounter no problems. Only when actually running the 
 code on a i386 will the problem appear. 
</quote>
mi sfugge qualcosa?
http://groups.yahoo.com/group/boost/message/1502
http://www.gotw.ca/gotw/045.htm
<cite from="un sito a caso">
 2.2.4.  Locks
 If you thought that ++i; would always work to add one to a variable, 
 you've got a nasty little surprise coming:  even if coded as a single
 instruction, the load and store of the result are separate memory 
 transactions, and other processors could access i between these two 
 transactions.  For example, having two processes both perform ++i; 
 might only increment i by one, rather than by two.
 According to the Intel Pentium "Architecture and Programming Manual",
 the LOCK prefix can be used to ensure that any of the following
 instructions is atomic relative to the data memory location it
 accesses:
______________________________________________________________________
  BTS, BTR, BTC                     mem, reg/imm
  XCHG                              reg, mem
  XCHG                              mem, reg
  ADD, OR, ADC, SBB, AND, SUB, XOR  mem, reg/imm
  NOT, NEG, INC, DEC                mem
  CMPXCHG, XADD
______________________________________________________________________
 However, it probably is not a good idea to use all these operations.
 For example, XADD did not even exist for the 386, so coding it may
 cause portability problems.
</cite>
nel caso specifico dell'op, la var non era neanche volatile.. ergo la
race sarebbe potuta esistere anche su una architettura che garantisca
atomicità sulle operazioni, non joinava i thread che spawnava, non
sincronizzava il set dell'int che sarebbe potuto acadere prima o dopo
che l'altro thread accedesse alla variabile.. ciò non toglie che il
problema potesse sussistere, per quanto improbabile, sempre che tu non
smentisca.
Uno sbirish che prova ad andare al mare un giorno ogni 65536, e quel
giorno piove.

 a cosa servirebbero le Interlocked* sui 32bit allora?
servono per test and set, scambio e incremento e decremento atomici, ma 
*non* singole letture/scritture. Tutte le operazioni implementate dalle 
funzioni Interlocked eseguono in un'istruzione sola una lettura *e* una 
scrittura: cosě evitano una possibile race condition
