Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Passaggio struct a thread
Forum - C/C++ - Passaggio struct a thread

Avatar
2_rici (Normal User)
Newbie


Messaggi: 11
Iscritto: 16/12/2010

Segnala al moderatore
Postato alle 21:33
Giovedì, 13/01/2011
salve,

mi sono creato una struct per passare più di un argomento ad un thread.
solo che in compilazione ottengo questo :yup:
Codice sorgente - presumibilmente VB.NET

  1. prove.c:162: error: no matching function for call to ‘matrix::matrix(void*&)
  2. prove.c:17: note: candidates are: matrix::matrix()
  3. prove.c:17: note:                 matrix::matrix(const matrix&)



creazione del thread
Codice sorgente - presumibilmente Plain Text

  1. matrix F, G;
  2.         F.stringa=indirizzo1.c_str();
  3.         F.dimensione=n;
  4.         F.M = A;
  5. rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);



funzione chiamata (parte saliente !)
Codice sorgente - presumibilmente C++

  1. void *fillMatrixWithSift(void *app){
  2.        
  3.         struct matrix fill;
  4.        
  5.         fill = (struct matrix) app;                         <--- riga 162.
  6.         const char *file = fill.stringa;
  7.         int n = fill.dimensione;       
  8.         int **val = fill.M;



la struct è questa
Codice sorgente - presumibilmente C++

  1. struct matrix {
  2.   const char *stringa;
  3.   int dimensione;
  4.   int **M;
  5. } F,G;



capisco (circa) cosa mi sta dicendo il compilatore però non vedo come porvi rimedio :_doubt:

grazie

Saluti

Ultima modifica effettuata da 2_rici il 13/01/2011 alle 21:36
PM
Avatar
TheKaneB (Member)
Guru^2


Messaggi: 1792
Iscritto: 26/06/2009

Up
1
Down
V
Segnala al moderatore
Postato alle 3:26
Venerdì, 14/01/2011
il compilatore si incazza perchè tenti di fare un casting senza senso...

Codice sorgente - presumibilmente C++

  1. void *fillMatrixWithSift(void *app){
  2.        
  3.         struct matrix fill;
  4.        
  5.         fill = &((struct matrix *) app);                         <--- riga 162.
  6.         const char *file = fill.stringa;
  7.         int n = fill.dimensione;        
  8.         int **val = fill.M;



così dovrebbe andare

PS: passare un puntatore ad una variabile locale ad un altro thread è una delle cose più sbagliate che tu possa fare.
Mi riferisco a questo:
Codice sorgente - presumibilmente Plain Text

  1. matrix F, G;
  2.         F.stringa=indirizzo1.c_str();
  3.         F.dimensione=n;
  4.         F.M = A;
  5. rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);


Quando il thread verrà eseguito, nessuno ti garantisce che lo stack dell'altra funzione (quella che ha creato il thread) sia ancora consistente con il momento della creazione del thread, quindi se ti funziona è solo per botta di culo.
Alloca SEMPRE nell'heap i dati condivisi tra 2 thread.

Ultima modifica effettuata da TheKaneB il 14/01/2011 alle 3:32
PM
Avatar
Xaratroom (Ex-Member)
Expert


Messaggi: 526
Iscritto: 03/04/2008

Up
0
Down
V
Segnala al moderatore
Postato alle 22:19
Giovedì, 13/01/2011
Prova a modificare il codice in questo modo:
Codice sorgente - presumibilmente C++

  1. void *fillMatrixWithSift(void *app) {
  2.         struct matrix *fill;
  3.         fill = app;
  4.         const char *file = fill->stringa;
  5.         int n = fill->dimensione;      
  6.         int **val = fill->M;



Come lo compili ?

PM
Avatar
Xaratroom (Ex-Member)
Expert


Messaggi: 526
Iscritto: 03/04/2008

Up
0
Down
V
Segnala al moderatore
Postato alle 8:22
Venerdì, 14/01/2011
Testo quotato

Postato originariamente da TheKaneB:

il compilatore si incazza perchè tenti di fare un casting senza senso...

Codice sorgente - presumibilmente C++

  1. void *fillMatrixWithSift(void *app){
  2.        
  3.         struct matrix fill;
  4.        
  5.         fill = &((struct matrix *) app);                         <--- riga 162.
  6.         const char *file = fill.stringa;
  7.         int n = fill.dimensione;        
  8.         int **val = fill.M;



così dovrebbe andare


Intendevi così ?
Codice sorgente - presumibilmente Plain Text

  1. fill = *((struct matrix *) app);


In ogni caso non vedo quale sia l'utilità di copiare l'intera struct nello stack del thread, quando puoi usare direttamente il puntatore (ovviamente se non vuoi modificare il valore della struttura originale basta stare attenti: io avrei tolto la variabile fill e mi sarei portato dietro il casting).

Testo quotato


Quando il thread verrà eseguito, nessuno ti garantisce che lo stack dell'altra funzione (quella che ha creato il thread) sia ancora consistente con il momento della creazione del thread, quindi se ti funziona è solo per botta di culo.
Alloca SEMPRE nell'heap i dati condivisi tra 2 thread.


Penso che, a fine main, faccia un join, quindi grossi problemi non ce ne sono (classica programmazione universitaria, che quando cerchi di cambiare qualcosina, non funziona più un cavolo).

Ultima modifica effettuata da Xaratroom il 14/01/2011 alle 8:26
PM
Avatar
2_rici (Normal User)
Newbie


Messaggi: 11
Iscritto: 16/12/2010

Up
0
Down
V
Segnala al moderatore
Postato alle 16:36
Venerdì, 14/01/2011
Codice sorgente - presumibilmente C++

  1. struct matrix *fill;
  2.        
  3. fill = (struct matrix *) app;
  4.  
  5.         const char *file = fill->stringa;
  6.         int n = fill->dimensione;      
  7.         int **val = fill->M;



ho risolto così, inizialmente passavo per puntatore fill solo che per accedere ai campi usavo

Codice sorgente - presumibilmente Plain Text

  1. fill.n = dimensione



e mi diceva che non era un operazione della struct matrix ma di matrix* ( un errore simile ora non ricordo benissimo ) così avevo tolto il puntatore a fill con risultato il suddetto errore :_doubt:

@ TheKaneB: non ho capito benissimo cosa intendi, io faccio la classica programmazione universitaria facendo la join nella funzione chiamante :D (qualsiasi consiglio per rimediare a ciò è ben accetto! )
@ Xaratroom: compilo così g++ -fopenmp -lpthread -o3 nome.c



PM
Avatar
TheKaneB (Member)
Guru^2


Messaggi: 1792
Iscritto: 26/06/2009

Up
0
Down
V
Segnala al moderatore
Postato alle 18:18
Venerdì, 14/01/2011
se io faccio un codice così:

Codice sorgente - presumibilmente C/C++

  1. int i=0;
  2. while (condizione)
  3. {
  4.     Tipo param;
  5.  
  6.     param.elemento = i;
  7.  
  8.     rc = pthread_create(&threads[0], &att, funzione, (void*) &param);
  9. }



supponiamo che venga creato il primo thread, questo entra in run ma subito lo scheduler decide che il suo timeslice è scaduto e passa il controllo nuovamente al main.
Il while fa un'altro ciclo, crea un nuovo oggetto "param", che nello stack avrà la stessa posizione del param dell'iterazione di prima, crea un nuovo thread e gli passa lo stesso indirizzo (in pratica passa sempre lo stesso indirizzo a tutti i thread).
Quando il primo thread si sarà svegliato, si ritroverà con il valore di "i" nuovo, anzichè quello precedente, perchè andando a leggere quell'indirizzo di memoria si ritroverà con dei dati sovrascritti dalla successiva iterazione del while.
La stessa cosa può accadere se, ad esempio, il thread viene assegnato ad un'altra CPU in un sistema multiprocessore/multicore, in modo tale da avere un parallelismo reale tra la creazione dei thread e i thread stessi.

Se il programma funziona è dovuto a queste 3 botte di culo combinate:
1) Lo scheduler lascia il nuovo thread in running per un periodo di tempo accettabile
2) Il thread arriva sempre a farsi una copia dei parametri, perchè lo fai nelle primissime istruzioni e quindi impiega poco tempo
3) Il thread viene spawnato sulla stessa CPU per massimizzare i cache hit di dati e istruzioni.

Queste 3 condizioni sono spesso vere, ma nessuno ti garantisce tale sicurezza.

In generale, quindi, è assolutamente vietato passare parametri ai thread usando lo stack.
Durante la creazione dei thread, fai semplicemente una new, o una malloc, allocando così la struct nell'heap. Poi dentro il thread stesso puoi tranquillamente fare la delete, o free, quando quell'oggetto non ti servirà più. In questo modo risolvi tutti i problemi.

@Xaratroom:
Testo quotato


Intendevi così ?
Codice sorgente - presumibilmente Plain Text

  1. fill = *((struct matrix *) app);





si, grazie per la correzione, ho scritto al volo senza troppo pensarci :-p

Ultima modifica effettuata da TheKaneB il 14/01/2011 alle 18:44
PM
Avatar
2_rici (Normal User)
Newbie


Messaggi: 11
Iscritto: 16/12/2010

Up
0
Down
V
Segnala al moderatore
Postato alle 19:26
Venerdì, 14/01/2011
Codice sorgente - presumibilmente Plain Text

  1. rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);
  2.         rc = pthread_create(&threads[1], &att, fillMatrixWithSift, (void*) &G);



in questo caso io ne creo solo due di thread e gli do il nome univoco di 0 al primo e 1 al secondo, ai due passo due strutture distinte che ognuno mette nel proprio stack.
Ho capito cosa intendi però credo di non avere questo problema (credo comunque :D )

in un'altra parte ho usato i thread e ho fatto così:

Codice sorgente - presumibilmente Delphi

  1. while (n>0){
  2.     for (int t=0; t<6; t++){
  3.         if (n>0){
  4.         indice = t + passi;
  5.         rc = pthread_create(&threads[t], &attr, sift_thread, (void*) indice);  
  6.         n--;
  7.         barriera++;}
  8.     }
  9.     for (int i=0; i<barriera; i++) {
  10.       rc = pthread_join(threads[i], NULL);
  11.       passi++;
  12.     }
  13.     barriera = 0;



per come la vedo io, ognuno di questi 6 thread avrà indice nel proprio stack, ipotizzando che lo scheduler tolga le risorse al primo thread appena è stato creato e lo riporta al master questi proseguirà con il ciclo for facendo le sue cose incrementerà indice e creerà un nuovo thread a cui passa un altro indice. Ora il controllo ritorna al primo thread creato il quale prenderà dal suo stack l'indice che, da quello che ne ho capito, è in uno spazio differente dallo stack del secondo thread creato perciò non dovrebbero esserci problemi.
Quando il master esce dal for aspetta tutti gli altri thread prima di ricrearli per il ciclo while e quindi di volta in volta ognuno avrà un proprio indice univoco da passare al proprio job..no?


il primo caso è comunque errato (leggi il mio post precedente con molta attenzione). Il secondo è corretto. - TheKaneB - 14/01/11 21:13
PM
Avatar
Xaratroom (Ex-Member)
Expert


Messaggi: 526
Iscritto: 03/04/2008

Up
0
Down
V
Segnala al moderatore
Postato alle 20:26
Venerdì, 14/01/2011
Testo quotato

Postato originariamente da 2_rici:

Codice sorgente - presumibilmente Plain Text

  1. rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);
  2.         rc = pthread_create(&threads[1], &att, fillMatrixWithSift, (void*) &G);



in questo caso io ne creo solo due di thread e gli do il nome univoco di 0 al primo e 1 al secondo, ai due passo due strutture distinte che ognuno mette nel proprio stack.
Ho capito cosa intendi però credo di non avere questo problema (credo comunque :D )

in un'altra parte ho usato i thread e ho fatto così:

Codice sorgente - presumibilmente Delphi

  1. while (n>0){
  2.     for (int t=0; t<6; t++){
  3.         if (n>0){
  4.         indice = t + passi;
  5.         rc = pthread_create(&threads[t], &attr, sift_thread, (void*) indice);  
  6.         n--;
  7.         barriera++;}
  8.     }
  9.     for (int i=0; i<barriera; i++) {
  10.       rc = pthread_join(threads[i], NULL);
  11.       passi++;
  12.     }
  13.     barriera = 0;



per come la vedo io, ognuno di questi 6 thread avrà indice nel proprio stack, ipotizzando che lo scheduler tolga le risorse al primo thread appena è stato creato e lo riporta al master questi proseguirà con il ciclo for facendo le sue cose incrementerà indice e creerà un nuovo thread a cui passa un altro indice. Ora il controllo ritorna al primo thread creato il quale prenderà dal suo stack l'indice che, da quello che ne ho capito, è in uno spazio differente dallo stack del secondo thread creato perciò non dovrebbero esserci problemi.
Quando il master esce dal for aspetta tutti gli altri thread prima di ricrearli per il ciclo while e quindi di volta in volta ognuno avrà un proprio indice univoco da passare al proprio job..no?


Funziona perché, come hai scritto anche tu, passi un valore intero nello spazio dedicato ad un indirizzo... Fortuna vuole che l'intero, in quello spazio, ci stia.
Se passi una variabile sullo stack, affinché il programma funzioni correttamente, devi assicurarti che quella variabile rimanga al suo posto per tutta l'esecuzione del thread.

Ma fate C o C++ ? perché compili come c++ se hai praticamente scritto codice C (dichiarazioni delle variabili a parte)

PM