Newsgroup: it.comp.lang.c
Titolo: Aiuto con thread

Ciao a tutti.
 
Ultimamente, per implementare un sistema di misura, sono dovuto ricorere ai thread.
 
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

Il 16/07/19 16:38, arkkimede ha scritto:

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
 
 
-- 
|___|

 |___|
 
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.....

Il 17/07/19 01:16, arkkimede 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 di non lasciare processi zombie? Grazie!
PS: Mi scuso per il doppio invio di mail ma avevo risposto dal email e non dal sito.

Il 17/07/19 10:44, arkkimede ha scritto:

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
 
-- 
|___|

 |___|
 
Tutto chiaro.
Grazie per l'aiuto.


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.

 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. 

 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
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   < 
http://giovanni.homelinux.net/
 >

Il 18/07/19 02:38, arkkimede ha scritto:

-- 
Appunto, dovrebbe
In pratica non hai la garanzia,anche se hai impostato stop a 0, che la 
istruzione eseguita dal main sia eseguita dopo la terminazione del 
thread stesso,dipende da come il kernel schedula
A questo serve pthread_join
 
|___|

 Giovanni
 
si,e' vero
Con una ottimizzazione abbastanza spinta l'ottimizzatore potrebbe 
addirittura eliminare la while
meglio dichiarala volatile per sicurezza
 
-- 
|___|

     pthread_exit(NULL);
 
Come detto su, questo non fa terminare il thread figlio ma il thread 
chiamante.

Il 18/07/19 14:27, 4ndre4 ha scritto:

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
 
 
-- 
|___|

Ringrazio tutti per i suggerimenti e consigli in particolare enoquick le cui indicazioni hanno da subito fatto funzionare il codice.
 
Alcune considerazioni a latere:
 
1 - Mi sembra strano che un ottimizzatore possa stravolgere un codice e trasformare un while(variabile) in un while(TRUE) ma non conosco i compilatori men che meno gli ottimizzatori, io li uso e basta, posso accettare questa verità espressa, probabilmente, da chi ne sa più di me. In ogni caso aggiungere volatile alla dichiarazione di stop non mi costa niente (già fatto) ed il codice continua a girare correttamente.
 
2 - Anche se non è necessaria la dichiarazione delle variabili restituite da malloc, preferisco lo stesso farla. Male non fa e mi rende il codice più leggibile.
 
3 - Conoscendo poco (o meglio per niente) la programmazione multi thread, cercavo qualcosa di minimale che potesse aiutarmi. Imbarcarmi in semafori, variabili mutex etc mi sembrava uno sforzo eccessivo rispetto alle mie necessità.
 
4 - Circa il nome stop, in realtà la variabile si chiama stopThread e personalmente (..de gustibus...) la preferisco ad active con logica booleana invertita.
 
Scusate il gioco di parole, ma per quanto mi riguarda considera il "thread" che ho aperto, chiuso. Adesso devo far girare il codice ed estrarre i risultati.
 
Grazie ancora

 Poi mi piace quel cast su malloc che in C vanno evitati
 
http://c-faq.com/malloc/mallocnocast.html
 
 
Stai zitto. Studia. Impara.

 4 - Circa il nome stop, in realtà la variabile si chiama stopThread e personalmente (..de gustibus...) la preferisco ad active con logica booleana invertita.
 
Bene, preferisci scrivere codice confusionario per chi legge. De gustibus.

Il 19/07/19 12:41, 4ndre4 ha scritto:

e' arrivato l'esperto
tutti giu il cappello
ritorna dalla tua tribu  di bradipi, fai la cosa migliore
 
 
-- 
|___|

Il 19/07/19 12:35, 4ndre4 ha scritto:

senti chi parla
la regola 2 del manuale non attacca con me,COGLIONE INCOMPETENTE
 
-- 
|___|

 e' arrivato l'esperto
 
Si`, io SONO esperto. Tu no. Taci e sparisci.

 la regola 2 del manuale non attacca con me,COGLIONE INCOMPETENTE
 
Stai zitto, IMBECILLE. Ti sei gia` ampiamente sputtanato dappertutto, 
COGLIONE.
 

 Si`, io SONO esperto. Tu no. Taci e sparisci.
 
pivello, qui come in it.comp.lang.c++ sono anni che scrivo quando capita
I tuoi unisci post non sono stati altro che meri pavoneggiamenti 
mischiati ad insulti verso altre persone.
Mai una riga di codice postata.
 
-- 
|___|

 Mai una riga di codice postata.
 
Ma stai zitto, DEMENTE. Il mio codice so dove postarlo e a chi postarlo, 
COGLIONE.
 
 

Il 20/07/19 06:19, 4ndre4 ha scritto:

ed ecco il bradipo sentendosi minacciato che torna alla difensiva 
emettendo i suoi classici vagiti
 
 
-- 
|___|

Il 20/07/19 01:07, 4ndre4 ha scritto:

ed ecco il solito bradipo di prima che continua con i suoi vagiti
 
-- 
|___|

 ed ecco il solito bradipo di prima che continua con i suoi vagiti
 
T-A-C-I.
 

 ed ecco il bradipo sentendosi minacciato che torna alla difensiva 
 
HAHAHAHAHAHAHAHAH... "minacciato"? E da chi? Da te? :D Ma se vali meno 
di una scureggia!
 
T-A-C-I.

 
 
while(true)
TACI();
 
 
 
 
-- 
|___|

 TACI();
 
Ecco bravo. Ora eseguitelo.


Non ho letto alcun messaggio di questa discussione, tuttavia di una cosa 
sono certo: sei un imbecille.
 
-- 
The three most dangerous things in the world are a programmer with a 
soldering iron, a hardware type with a program patch and a user with an 
idea.
 
“Alles hat ein Ende, nur die Wurst hat zwei”

 enoquick), conosce.
Bah, in *questo specifico caso*, se proprio manca l' header il 
compilatore da gia' un warning sulla mancanza del prototipo , quindi 
cast o meno non cambia nulla a livello di avvertimento all' utente,
sempre che non si lavori con compilatori del secolo scorso :-)
 
In ogni caso,la funzione malloc(), se trovata dal linker ritorna un 
puntatore corretto,che viene correttamete caricato nella variabile,
cast o meno, per cui la 'best pratices' in questione in realta' e' solo 
... fuffa.
aa

 > 
 
In questo gruppo di discussione nel corso degli anni ho sempre avuto un aiuto che mi ha risolto i problemi che a volte incontro nella programmazione.
Negli ultimi anni però tendo ad evitare perché ogni volta si scatenano diatribe tra Tizio che offende Caio dandogli dell'incompetente perché la verità assoluta ce la ha solo Tizio. A questo punto Caio risponde etc. etc. etc.
 
In poche parole il gruppo si é inaridito e ci sono pochissime domande.
 
Sarebbe bello che il gruppo riprendesse ad essere frequentato, magari un problema di un altro può essere utile anche a me.
 
Quello che ci vorrebbe è un maggior rispetto degli altri.
 
Quello che penso io è diverso da quello che pensi tu e lo si può dire in maniera civile senza offendere e trascendere.
 
Non sono un troll (sono anche andato a vedere cosa voleva dire) ma solo una persona che a volte ha bisogno dell'espereinza di chi ne sa di più di me.

 In poche parole il gruppo si é inaridito e ci sono pochissime domande.
 
Diciamo che nel gruppo ci sono pochissime domande forse perche' le 
problematiche del linguaggio C, a cui il gruppo e' dedicato, sono meglio 
trattate altrove. Ad esempio su stackoverflow, ma le risorse in rete 
sono pressoche' infinite.
Si aggiunga il fatto che, a sentimento, mi sembra sia lecito affermare 
che il C non sia piu' il linguaggio di punta di una volta. Ad esempio 
sono almeno 15 anni che non mi capita piu' di iniziare nuovi progettti 
in C, anche se mi capita di mettere le mani su sorgenti anche di piu' di 
20 anni fa.

On Friday, 30 August 2019 15:33:08 UTC+1, CortexA57  wrote:
 
[...]
Ma quale fuffa! Ma quali compilatori del secolo scorso! Ma che cazzo stai dicendo! Hai almeno capito cosa c'e` scritto a quel link? Ma la finite di scrivere cazzate? Volete informarvi, per una buona volta? Leggere, studiare e capire? Cosa cazzo c'entra il "livello di avvertimento all'utente"? Cosa cazzo sarebbe un "puntatore corretto"? Ma andate a studiare!!!
 

 Quello che ci vorrebbe è un maggior rispetto degli altri.
 
No, quel che ci vuole e` che gli inesperti come te accettino i consigli, ringrazino, e abbassino la testa, piuttosto che rispondere con un "grazie, ma continuo a fare come mi pare". Se non vuoi essere tacciato d'essere un troll, non ti comportare da troll.


ragazzo, tu devi avere qualche problema :-)
 

FYI
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>#include <stdio.h>     /* printf, scanf, NULL */
//#include <stdlib.h>  /* malloc, free, rand */  <== manca 'header
#include <string.h>
 
typedef struct _cc_{
   int   ixx;
   char  i8;
}CC_T;
 
int main(int argc, char *argv[])
{
    CC_T* pmem=NULL;
    pmem= malloc(sizeof(CC_T) );
    return 0;
}
 
Risultato compilazione:
implicit declaration of function 'malloc' [-Wimplicit-function-declaration]
assignment makes pointer from integer without a cast [-Wint-conversion]
1> Linking demo.elf
Build complete
 
Va da se' che il primo warning è sufficiente per rilevare il problema,
anche se chi ha studiato probabilmente necessita anche dell' ulteriore 
warning sul cast :-)
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
#include <stdio.h>     /* printf, scanf, NULL */
//#include <stdlib.h>  /* malloc, free, rand */ <== manca header
#include <string.h>
 
typedef struct _cc_{
   int   ixx;
   char  i8;
}CC_T;
 
int main(int argc, char *argv[])
{
    CC_T* pmem=NULL;
    pmem= (CC_T*)malloc(sizeof(CC_T) );
   return 0;
}
Risultato compilazione:
implicit declaration of function 'malloc' [-Wimplicit-function-declaration]
1> Linking demo.elf
Build complete
 
Idem come sopra, anche il cast elimina un warning
NB. in fase di link l' indirizzo della funzione malloc è risolto
correttamete ed il codice funziona comunque (ma non è una bella pratica,
la mancanza dell' header, non il cast).
 
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <stdio.h>     /* printf, scanf, NULL *
#include <stdlib.h>  /* malloc, free, rand */
#include <string.h>
 
typedef struct _cc_{
   int   ixx;
   char  i8;
}CC_T;
 
int main(int argc, char *argv[])
{
    CC_T* pmem=NULL;
    pmem= (CC_T*)malloc(sizeof(CC_T) );
    pmem= malloc(sizeof(CC_T) );		// :-)
    return 0;
}
Risultato compilazione:
1> Linking demo.elf
Build complete
 
No warnings :-)
 
AA
 
 
 

 anche di piu' di 20 anni fa.
 
Beh, in ambito industriale magari no.  Vedo che C++ fa
da padrone in quelli che credo fossero gli ambiti del C
in passato.  Poi ci sono cose di moda come il Go ed il
Rust, ma secondo me finisce un po' come con ObjectiveC
e amici.
 
Parliamo di kernel?  No dai, ma si potrebbe.
 
In termini di progetti personali, credo che il C abbia
ancora il suo bel posticino.
 
Parlo poi per me: gli ultimi due progetti che ho
scritto sono in C.  Penso che se prendi la smeplicità
del C e ci metti UtHash per sopperire all'assenza
dell'indispensabile hash table, hai l'ambiente
perfetto: semplice e senza troppe cazzabubbole.  Veloce
come una furia a compilare.
 
Per finire, il Tiobe Index lo riporta sempre e comunque
al primo o al secondo posto, assieme a quel vecchio
minchione di Java.
 
Per finire, stavolta davvero, consiglio la lettura di
http://250bpm.com/blog:4