Oppure

Loading
13/01/11 20:33
2_rici
salve,

mi sono creato una struct per passare più di un argomento ad un thread.
solo che in compilazione ottengo questo :yup:
prove.c:162: error: no matching function for call to ‘matrix::matrix(void*&)’
prove.c:17: note: candidates are: matrix::matrix()
prove.c:17: note:                 matrix::matrix(const matrix&)



creazione del thread
matrix F, G;
	F.stringa=indirizzo1.c_str();
	F.dimensione=n;
	F.M = A;
rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F); 


funzione chiamata (parte saliente !)
void *fillMatrixWithSift(void *app){
	
	struct matrix fill;
	
	fill = (struct matrix) app;                         <--- riga 162.
	const char *file = fill.stringa;
	int n = fill.dimensione;	
	int **val = fill.M;


la struct è questa
struct matrix {
  const char *stringa;
  int dimensione;
  int **M;
} 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 13/01/11 20:36
aaa
13/01/11 21:19
Xaratroom
Prova a modificare il codice in questo modo:
void *fillMatrixWithSift(void *app) {
	struct matrix *fill;
	fill = app;
	const char *file = fill->stringa;
	int n = fill->dimensione;	
	int **val = fill->M;


Come lo compili ?
aaa
14/01/11 2:26
TheKaneB
il compilatore si incazza perchè tenti di fare un casting senza senso...

void *fillMatrixWithSift(void *app){
        
        struct matrix fill;
        
        fill = &((struct matrix *) app);                         <--- riga 162.
        const char *file = fill.stringa;
        int n = fill.dimensione;        
        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:
matrix F, G; 
        F.stringa=indirizzo1.c_str(); 
        F.dimensione=n; 
        F.M = A; 
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 14/01/11 2:32
aaa
14/01/11 7:22
Xaratroom
Postato originariamente da TheKaneB:

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

void *fillMatrixWithSift(void *app){
        
        struct matrix fill;
        
        fill = &((struct matrix *) app);                         <--- riga 162.
        const char *file = fill.stringa;
        int n = fill.dimensione;        
        int **val = fill.M;


così dovrebbe andare

Intendevi così ?
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).

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 14/01/11 7:26
aaa
14/01/11 15:36
2_rici
	struct matrix *fill; 
	
fill = (struct matrix *) app;

	const char *file = fill->stringa;
	int n = fill->dimensione;	
	int **val = fill->M; 


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

 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


aaa
14/01/11 17:18
TheKaneB
se io faccio un codice così:

int i=0;
while (condizione)
{
    Tipo param;

    param.elemento = i;

    rc = pthread_create(&threads[0], &att, funzione, (void*) &param);
}



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:
Intendevi così ?
fill = *((struct matrix *) app);



si, grazie per la correzione, ho scritto al volo senza troppo pensarci :-p
Ultima modifica effettuata da TheKaneB 14/01/11 17:44
aaa
14/01/11 18:26
2_rici
	rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);
	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ì:

	while (n>0){ 
    for (int t=0; t<6; t++){
	if (n>0){
	indice = t + passi;
	rc = pthread_create(&threads[t], &attr, sift_thread, (void*) indice);  
	n--; 
	barriera++;}
    }
    for (int i=0; i<barriera; i++) { 
      rc = pthread_join(threads[i], NULL); 
      passi++;
    } 
    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?

aaa
14/01/11 19:26
Xaratroom
Postato originariamente da 2_rici:

	rc = pthread_create(&threads[0], &att, fillMatrixWithSift, (void*) &F);
	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ì:

	while (n>0){ 
    for (int t=0; t<6; t++){
	if (n>0){
	indice = t + passi;
	rc = pthread_create(&threads[t], &attr, sift_thread, (void*) indice);  
	n--; 
	barriera++;}
    }
    for (int i=0; i<barriera; i++) { 
      rc = pthread_join(threads[i], NULL); 
      passi++;
    } 
    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)
aaa