PDA

Visualizza la versione completa : [C++] - Gestione variabile multi-thread


alfa_19
02-01-2012, 18:58
Salve a tutti.

Io ho 4 thread che eseguono tutti la stessa funzione.

Per semplicità facciamo che questa funzione faccia semplicemente la somma di 2 numeri.

Ora, quello che io voglio fare è far si che in base a quale thread stia in quel momento eseguendo l'operazione, i 2 addendi siano diversi.

Per spiegarmi meglio posto un piccolo pseudo-codice:


int somma(){

int a,b

if (sei il thread 1) then {
a = 1;
b = 2;
}
if (sei il thread 2) then {
a = 3;
b = 4;
}

return a+b;

}

inizio subito col dire che quel if (sei il thread ... ) funziona bene perchè comunico con i thread mediante messaggi WM_USER; quindi il thread entra solo nell'if che lo riguarda (testato).
sempre per il motivo che comunico tramite messaggi, non mi è possibile passare a e b come parametri alla funzione, quindi questa opzione anche non è da considerare.

detto questo passiamo al problema vero e proprio: facendo così, il primo thread arriva e pone a=1 e b=2; poi la cpu passa al secondo thread che pone a=3 e b=4; poi quando la cpu ritorna al primo thread, che deve ritornare la somma, lui ritorna 7 perchè di fatto la variabile è stata aggiornata dall'altro thread.

non c'è un modo per far si che ogni thread si tenga le sue variabili?

l'unica alternativa che mi è venuta è quella di fare un vettore di 8 interi, dove il thread 1 usa i primi due, il thread 2 i successivi e così via, ma mi sembra un inutile spreco di risorse...anche perchè se le variabili invece di essere 2 diventano 10 e i thread invece di 4 diventano 20, devo allocare 200 variabili al posto di 10!

Grazie mille per chi mi risponderà, spero di essere stato abbastanza chiaro :)

oregon
02-01-2012, 19:07
Passa i valori ai thread come parametri quando li crei.

alfa_19
02-01-2012, 19:14
mmmm.....soluzione semplice, perchè non ci ho pensato?

però se invece la situazione fosse questa:

all'interno della funzione ogni thread deve eseguire il codice sopra ogni volta che riceve un messaggio di tipo WM_USER+1.

Quindi ci sarà un while(GetMessage...).

supponiamo che le variabili a e b possano essere calcolate ad ogni iterazione (ad esempio a partire da valori nelle var. globali) ma non è detta che siano le stesse ad ogni iterazione.

in questo caso non funzionerebbe più passare alla creazione, e non posso nemmeno passare nel messaggio perchè wParam lo uso già per altro

oregon
02-01-2012, 19:18
Non ho capito ...

Se passi i valori iniziali alla creazione del thread e li memorizzi in due variabili all'interno del thread, cosa c'entra poi il resto?

E, in ogni caso, che vuoi dire con "wParam lo uso già per altro"?

Sicuramente, se mostrassi il codice concreto, si capirebbe meglio ...

alfa_19
02-01-2012, 19:29
ma il codice completo son oltre 600 righe, un pò lunghetto....e oltretutto non è nemmeno su questo pc :)

dunque, mi spiego meglio

1) per wParam: quando si invia un WM Message si possono utilizzare 2 parametri: wParam e lParam. Io uno lo uso già per altri scopi, quindi ne resta disponibile solamente un altro. E quindi in un solo parametro non riesco ad inviare sia a che b.

2) io voglio eseguire il codice ad ogni arrivo di messaggio. quindi io avrò un codice di questo tipo


int funzione(){

while(GetMessage(...)){
if (sei il thread 1) then {
a = golbal+1;
b = golbal+2;
}
if (sei il thread 2) then {
a = golbal+3;
b = golbal+4;
}

....some code....
}

return 0;

}

in pratica il thread continua a ciclare dentro quel while fino a quando il programma non termina.

GetMessage è bloccante, quindi il codice all'interno del while viene eseguito solo alla ricezione di un messaggio.

la variabile global è globale, e non è detta che da un'iterazione all'altra sia rimasta inalterata.

MItaly
02-01-2012, 19:37
Allora dinamicamente una struct che contiene i due parametri, riempila con i valori da passare e passa un puntatore ad essa in lParam. Quando nel thread non ti servono più i parametri deallocala.

oregon
02-01-2012, 19:38
Originariamente inviato da alfa_19
1) per wParam ...


Con lParam si usa passare un puntatore ad una struttura dove ci sono tutti i dati che vuoi.



2) io voglio eseguire il codice ad ogni arrivo di messaggio ...

la variabile global è globale, e non è detta che da un'iterazione all'altra sia rimasta inalterata.

Attenzione quando si trattano variabili condivise tra thread. Se non prevedi una "sincronizzazione" di scritture/letture potresti avere brutte sorprese.

Per il resto, se in

a = global+1

a è una variabile locale al thread (ecco a cosa serviva il sorgente, non tutto ma le piccole parti relative al problema ...), non capisco ancora cosa dovresti passare tramite il messaggio ...

alfa_19
02-01-2012, 19:41
si lo so che su lParam posso mettere il puntatore, ma a questo punto è la stessa cosa di dichiarare un array[8] come descritto nel mio primo post.

il problema è che se io lascio il codice così com'è (si a è locale) arriva il thread 1 che pone a=global+1; poi la cpu passa al thread 2 che pone a=global+3; poi la cpu ritorna al thread 1 che fa quello che deve fare ma con il valore di a sbagliato.

oregon
02-01-2012, 19:49
Sì ma non puoi pretendere la botte piena e la moglie ubriaca ... se ti servono delle variabili diverse per thread, le devi allocare. Se non vuoi allocare spazio perché secondo te è sprecato, allora avrai delle variabili comuni. Non mi pare ci sia alternativa.

Puoi utilizzare delle variabili "per thread" sfruttando il

Thread Local Storage

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686749(v=vs.85).aspx

scrivendo ad esempio

__declspec( thread ) int tls_i = 1;

ma la questione non cambia ... avrai utilizzato una variabile per thread.

alfa_19
02-01-2012, 20:00
ok grazie :)

Loading