faretesto > comp.lang.* > comp.lang.c

arkkimede (16.07.2019, 23:38)
Ciao a tutti.

Ultimamente, per implementare un sistema di misura, sono dovuto ricorere aithread.

In poche parole, ho un codice che deve gestire tutta la stuentazione che costituisce il banco di misura ed in parallelo devo anche ricevere da un socket udp de dati che rappresentano le misure.
Allora ho implementato un thread che carica i dati udp in delle variabili globali che poi il sistema di misura, quando ne ha bisogno, va a leggere.

Se un ipotetico main esegue questa procedura una sola volta, il tutto sembra funzionare, se devo ripeterlo due volte, non mi funziona.

Per semplificare l'aiuto, ho provato a scrivere un esempio di quello che intendo
che riporto di seguito.
Premetto che:
come è ovvio non conosco i thread e li uso cercando di scopiazzare qualche esempio trovato in rete (ed in fatti non funziona), quindi siate clementi e pazienti.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define NDAT 4
#define NMEAS 10

// Dichiarazoni variabili globali
int stop = 1;
double vect[NDAT];
long long int counter = 0;

// Implementazione del Thread
void *myThreadFun(void *vargp)
{

while(stop)
{
for(int i=0; i<NDAT; i++)
vect[i] = drand48();
counter++;
}

return NULL;
}
int main()
{
// Dichiarazioni variabili locali al main
double **meas;
pthread_t thread_id;
long long int *index;

meas = (double **)malloc(sizeof(double *)*NDAT);
for(int i=0; i<NDAT; i++)
meas[i] = (double *)malloc(sizeof(double)*NMEAS);

index = (long long int *)malloc(sizeof(long long int)*NMEAS);

// Creazone del thread
pthread_create(&thread_id, NULL, myThreadFun, NULL);

// Caricamento delle varibili locali con quelle valorizzate dal thread
for(int i=0; i<NMEAS; i++)
{
usleep(1000000/25);
for(int j=0; j<NDAT; j++)
{
meas[j][i] = vect[j];
}
index[i]=counter;
}

// Interruzione del loop del thread
stop = 0;
// Stampa variabili locali
printf("Primo Thread\n");
for (int i=0; i<NMEAS; i++)
{
printf("%11lld ",index[i]);
for(int j=0; j<NDAT; j++)
printf("%12.7lf ",meas[j][i]);
printf("\n");
}

pthread_exit(NULL);

// Reinizializzazione della variabile che genera il loop nel thread
stop=1;

// Ricreazione del thread
pthread_create(&thread_id, NULL, myThreadFun, NULL);

// Ricaricamento delle varibili locali con quelle valorizzate dal thread
for(int i=0; i<NMEAS; i++)
{
usleep(1000000/25);
for(int j=0; j<NDAT; j++)
{
meas[j][i] = vect[j];
}
index[i]=counter;
}

// Re interruzione del loop del thread
stop = 0;

// Ristampa delle variabili locali
printf("Secondo Thread\n");
for (int i=0; i<NMEAS; i++)
{
printf("%6lld ",index[i]);
for(int j=0; j<NDAT; j++)
printf("%12.7lf ",meas[j][i]);
printf("\n");
}

pthread_exit(NULL);
return(0);
}

In poche parole, il thread valorizza ripetutamente un vettore con delle variabili casuali ed in più incrementa un contatore.

Il main inizializza il thread la prima volta e si carica in variabili locali le variabili gestite dal thread.

Dopo un certo numero di misure chiude il thread stampa i risultati e poi cerca di far ripartire il thread ma questo non parte più.

Potreste aiutarmi a far ripartire il thread?

Infatti l'uscita del codice è:

Primo Thread
162599 0.3650915 0.2275736 0.2588753 0.1658872
340999 0.8107834 0.8994204 0.0367229 0.3529654
542425 0.9573723 0.5105165 0.5303837 0.3572413
753444 0.0886289 0.5935065 0.2052967 0.5270124
969412 0.0342385 0.3317079 0.0559487 0.4502195
1166706 0.3764532 0.8151522 0.4696074 0.9440458
1374246 0.7098990 0.5037660 0.8878479 0.7803547
1580564 0.3848518 0.5625821 0.4060749 0.8265282
1790795 0.4446809 0.2702366 0.0106942 0.9583127
2004404 0.0010914 0.5191977 0.7429309 0.8507132

ma il secondo non appare.

Grazie
enoquick (17.07.2019, 03:27)
Il 16/07/19 16:38, arkkimede ha scritto:
[..]
> 2004404 0.0010914 0.5191977 0.7429309 0.8507132
> ma il secondo non appare.
> Grazie


Per forza, pthread_exit fa terminare il main quando l'ultimo thread
finisce (e tu ne hai uno)

dal man
After the last thread in a process terminates, the process terminates
as by calling exit(3) with an exit status of zero;

per usare i threads usa una cosa del genere

stop=1; //altrimenti il thread esce subito
if (pthread_create(&thread_id, NULL, myThreadFun, NULL)) {
//error
}
sleep(5); //attende 5 sec - intanto il thread fa le sue cose
stop = 0; // fa uscire il thread
if (pthread_join(thread_id,NULL)) { //attende che il thread termini
//error
}
//elabora il risultato
arkkimede (17.07.2019, 08:14)
Il giorno mercoledì 17 luglio 2019 03:27:05 UTC+2, enoquick ha scritto:
[..]
> //elabora il risultato
> --
> |___|


Prima di tutto grazie per la risposta!
Quindi il mio errore era usare il primo pthread_exit.
In effetti eliminando quello il codice gira.

Poi, solo per essere sicuro, nelle righe di codice che riporti, restituendo
0 sia pthread_create sia pthread_join in caso di successo, forse gli if andavano negati? (if(!pthread_create()) .... if(!pthread_join())...
Comunque grazie
arkkimede (17.07.2019, 08:16)
Il giorno mercoledì 17 luglio 2019 08:14:26 UTC+2, arkkimede ha scritto:
> Il giorno mercoledì 17 luglio 2019 03:27:05 UTC+2, enoquick ha scritto:
> Prima di tutto grazie per la risposta!
> Quindi il mio errore era usare il primo pthread_exit.
> In effetti eliminando quello il codice gira.
> Poi, solo per essere sicuro, nelle righe di codice che riporti, restituendo
> 0 sia pthread_create sia pthread_join in caso di successo, forse gli if andavano negati? (if(!pthread_create()) .... if(!pthread_join())...
> Comunque grazie


Mi rispondo da solo, NO perché quello era il caso di errore.....
enoquick (17.07.2019, 14:07)
Il 17/07/19 01:16, arkkimede ha scritto:
> Il giorno mercoledì 17 luglio 2019 08:14:26 UTC+2, arkkimede ha scritto:
> Mi rispondo da solo, NO perché quello era il caso di errore.....


ma nel tuo codice esiste un altro errore, a parte togliere pthread_exit
se vuoi essere certo che il thread sia terminato (e normalmente e'cosi)
questo lo si fa con pthread_join
arkkimede (17.07.2019, 17:44)
Il giorno mercoledì 17 luglio 2019 14:07:11 UTC+2, enoquick ha scritto:
> ma nel tuo codice esiste un altro errore, a parte togliere pthread_exit
> se vuoi essere certo che il thread sia terminato (e normalmente e'cosi)
> questo lo si fa con pthread_join
> --
> |___|


Adesso, seguendo il tuo suggerimento lo ho aggiunto.
inoltre tu dici:
".. se vuoi essere certo che il thread sia terminato (e normalmente e'cosi)
questo lo si fa con pthread_join"

Volevo allora chiederti un chiarimento/conferma.

Tralasciando l'esempio che ho postato solo per chiarire il problema, l'acquisizione dei dati tramite thread è solo la parte iniziale. Detti dati devono poi comunque essere elaborati.
E' allora sufficiente usare solo pthread_join o comunque bisogna usare pthread_exit (per esempio come ultima istruzione del main) per essere sicuro dinon lasciare processi zombie? Grazie!
PS: Mi scuso per il doppio invio di mail ma avevo risposto dal email e non dal sito.
enoquick (17.07.2019, 18:03)
Il 17/07/19 10:44, arkkimede ha scritto:
> Il giorno mercoledì 17 luglio 2019 14:07:11 UTC+2, enoquick ha scritto:
> Adesso, seguendo il tuo suggerimento lo ho aggiunto.
> inoltre tu dici:
> ".. se vuoi essere certo che il thread sia terminato (e normalmente e'cosi)
> questo lo si fa con pthread_join"
> Volevo allora chiederti un chiarimento/conferma.
> Tralasciando l'esempio che ho postato solo per chiarire il problema, l'acquisizione dei dati tramite thread è solo la parte iniziale. Detti dati devono poi comunque essere elaborati.
> E' allora sufficiente usare solo pthread_join o comunque bisogna usare pthread_exit (per esempio come ultima istruzione del main) per essere sicuro di non lasciare processi zombie? Grazie!
> PS: Mi scuso per il doppio invio di mail ma avevo risposto dal email e non dal sito.


pthread_join attende che un solo thread fra tutti i thread esistenti
termini, non tutti i thread
quindi per non lasciare zombi devi essere certo che altri thread non
siano esistenti
pthread_exit,nel main, prendila come caso limite per l'uscita (tipo una
exit() od un abort()), normalmente non e' necessaria
Per la precisione, se so che non ho altri thread che girano inutile
chiamare pthread_exit() nel main
Un thread quando esce fa una chiamata implicita a pthread_exit
arkkimede (18.07.2019, 07:21)
Il giorno mercoledì 17 luglio 2019 18:03:34 UTC+2, enoquick ha scritto:
[..]
> Un thread quando esce fa una chiamata implicita a pthread_exit
> --
> |___|


Tutto chiaro.
Grazie per l'aiuto.
Dr.UgoGagliardelli (18.07.2019, 08:12)
Il 17.07.2019 17.44, arkkimede ha scritto:
> Il giorno mercoledì 17 luglio 2019 14:07:11 UTC+2, enoquick ha scritto:
> Adesso, seguendo il tuo suggerimento lo ho aggiunto.
> inoltre tu dici:
> ".. se vuoi essere certo che il thread sia terminato (e normalmente e'cosi)
> questo lo si fa con pthread_join"
> Volevo allora chiederti un chiarimento/conferma.
> Tralasciando l'esempio che ho postato solo per chiarire il problema, l'acquisizione dei dati tramite thread è solo la parte iniziale. Detti dati devono poi comunque essere elaborati.
> E' allora sufficiente usare solo pthread_join o comunque bisogna usare pthread_exit (per esempio come ultima istruzione del main) per essere sicuro di non lasciare processi zombie? Grazie!


Diciamo che se ti aspetti il termine ordinato del thread, dovresti
utilizzare pthread_join, il cui scopo e' di attendere fino al termine
del thread, che potrebbe non arrivare mai se non hai preventivamente
instaurato un meccanismo per richiedere al thread di terminare
autonomamente.
Nel tuo caso, mi sembra di capire che ogni thread sia dedicato alla
lettura di dati da unita' esterne, per cui probabilmente non e'
strettamente necessaria una chiusura ordinata, quindi utilizzare
pthread_exit potrebbe essere auspicabile.
In ogni caso tieni presente che invocando pthread_exit, vengono invocati
gli handler di cleanup registrati, che ad esempio possono iniziare la
chiusura ordinata di cui sopra.
arkkimede (18.07.2019, 09:38)
Il giorno giovedì 18 luglio 2019 08:13:57 UTC+2, Dr.UgoGagliardelli hascritto:
[..]
> In ogni caso tieni presente che invocando pthread_exit, vengono invocati
> gli handler di cleanup registrati, che ad esempio possono iniziare la
> chiusura ordinata di cui sopra.


I thread sono ordinati: la stessa funzione acquisisce i valori delle due componenti ortogonali di un campo elettrico (e dovendo poi ricomporle, anche i dati devono essere ordinati);
è previsto un meccanismo che garantisce la chiusura del thread, vedi codice riportato come primo msg: la variabile stop che fa uscire dal loop infinito che costituisce il thread.
Quindi credo che la soluzione ottimale sia quella di utilizzare solo pthread_join, come ulteriore protezione, anche se il thread dovrebbe morire appena stop è settata a 0.
Grazie comunque del messagio.
Giovanni (18.07.2019, 12:43)
On 07/18/2019 09:38 AM, arkkimede wrote:
> Quindi credo che la soluzione ottimale sia quella di utilizzare solo
> pthread_join, come ulteriore protezione, anche se il thread dovrebbe
> morire appena stop è settata a 0. Grazie comunque del messagio.


Io vedo un problema proprio in quella variabile 'stop'. Ho avuto
difficoltà perché l'ottimizzazione del compilatore eliminava il test del
while. Per evitarlo 'stop' andrebbe dichiarata 'volatile'.

Ciao
Giovanni
enoquick (18.07.2019, 14:35)
Il 18/07/19 02:38, arkkimede ha scritto:
[..]
enoquick (18.07.2019, 14:39)
Il 18/07/19 05:43, Giovanni ha scritto:
> On 07/18/2019 09:38 AM, arkkimede wrote:
> Io vedo un problema proprio in quella variabile 'stop'.  Ho avuto
> difficoltà perché l'ottimizzazione del compilatore eliminava il test del
> while.  Per evitarlo 'stop' andrebbe dichiarata 'volatile'.
> Ciao
> Giovanni


si,e' vero
Con una ottimizzazione abbastanza spinta l'ottimizzatore potrebbe
addirittura eliminare la while
meglio dichiarala volatile per sicurezza
4ndre4 (18.07.2019, 21:27)
On 16/07/2019 22:38, arkkimede wrote:

> come è ovvio non conosco i thread e li uso cercando di scopiazzare qualche esempio trovato in rete (ed in fatti non funziona), quindi siate clementi e pazienti.


pthread_exit fa uscire il thread specifico passando un exit code al
parent (tipicamente il thread che chiama pthread_join), quindi il tuo
non e` l'uso corretto. Nel tuo caso, comunque, non credo serva far
ripartire il thread tutte le volte. Hai bisogno di tenere un thread di
lettura dal socket attivo, memorizzare i dati in una struttura dati
sincronizzata e leggerli da un altro thread.
Non usare variabili (vedi la tua 'stop') per sincronizzare i thread. Usa
i costrutti di sincronizzazione appositi (semafori, mutex, etc..)

Qualche nota sul tuo codice:

> while(stop)


'stop' non e` un nome fantastico per una variabile di loop come questa.
un nome come 'active' sarebbe meglio (con logica booleana invertita,
ovviamente).

> meas = (double **)malloc(sizeof(double *)*NDAT); [...]
> meas[i] = (double *)malloc(sizeof(double)*NMEAS); [...]
> index = (long long int *)malloc(sizeof(long long int)*NMEAS);


I cast sui valori di ritorno di malloc() non sono necessari in C
(obbligatori in C++ ma in C vanno evitati).

> pthread_exit(NULL);


Come detto su, questo non fa terminare il thread figlio ma il thread
chiamante.
enoquick (19.07.2019, 01:18)
Il 18/07/19 14:27, 4ndre4 ha scritto:
[..]
> (obbligatori in C++ ma in C vanno evitati).
> Come detto su, questo non fa terminare il thread figlio ma il thread
> chiamante.


arrivi tardi pivello
Perche non hai esposto la tua grande conoscenza di C al momento giusto ?
Poi mi piace quel cast su malloc che in C vanno evitati, per i pivelli
puo essere una conseguenza grave quanto la fine del mondo

Discussioni simili