[C] Cast void->int thread

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

[C] Cast void->int thread

Messaggio da gila75 »

Ciao a tutti. Sto iniziando a studiare i thread, e da quanto ho capito gli argomenti a funzione si possono passare solo a variabile singola,strutture,
array.
Non capisco il perchè il prototipo è di tipo void, non si poteva semplicemente fare come le funzioni normali?
Comunque, passando una variabile ok, è facile, ma passando un array non sono sicuro che il mio cast void->int sia il "massimo"

Codice: Seleziona tutto

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>


    
void *PrintHello(void *array)
{
    int *m;
    int i;
    printf("Hello World!");
    m=array;
    for (i=0; i<10; i++)
    {
        m[i]=*((int *)array);
        m[i]=i;
        printf ("%d\n",m[i]);
    }

    pthread_exit (NULL);}

int main(void)
{
    pthread_t mio_3d;
    int rc;
    int array[10];
    printf("Creo thread ");
        rc = pthread_create (&mio_3d, NULL, PrintHello,(void *)array);
        if (rc!=0)
        {
            printf("ERRORE:  %d\n",rc);
            exit(-1);
        }
    
    pthread_exit (NULL);
}
è corretto?
Magari se qualcuno mi spiega anche perchè ogni volta dover fare il cast...Perchè l'hanno pensata così e non come le funzioni "normali" ?
Grazie a tutti in anticipo
ale4
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 761
Iscrizione: venerdì 10 agosto 2012, 17:53

Re: [C] Cast void->int thread

Messaggio da ale4 »

Il cast lo puoi fare, non da alcun problema, la motivazione è semplice, void * indica un puntatore generico, che quindi va bene per qualsiasi tipo di dato. È un po' l'equivalente dell'Object in Java se hai mai visto quel linguaggio sostanzialmente, un tipo che può contenere qualsiasi tipo di puntatore.

Il motivo per cui è stato reso necessario è che la funzione pthread_create prende come terzo argomento un puntatore a funzione della forma void * (*funzione)(void *), non potevano fare altrimenti in quanto il C non ha a differenza di altri linguaggi come il C++ i tipi generici, che avrebbero consentito la definizione di un puntatore a funzione in grado di accettare qualsiasi parametro.

In ogni caso non fa alcuna differenza alla fin fine, sempre di un tipo puntatore si tratta, alla fine tutti i tipi puntatori sono uguali come rappresentazione in memoria a basso livello, nel senso che occupano lo stesso numero di byte, quindi il cast non comporta alcun problema, il tipo serve solamente come un indicazione per il compilatore sostanzialmente (in modo tale che quando accedi ad un array di int il compilatore sa che deve spostarsi avanti di 4 byte piuttosto che di 1 nel caso di un array di char).

Volendo con certe precauzioni puoi fare anche il cast di una qualsiasi variabile non puntatore in void *, ma bisogna starci molto molto attenti, in quanto void * è dipendente dall'architettura in uso, e ti puoi ritrovare con un codice che funziona benissimo se compilato a 64 bit e un po' meno bene se compilato a 32, quindi è considerata una pratica di cattiva programmazione e da evitare a meno di non essere assolutamente certi che funzioni su tutte le architetture (una volta mi è capitato un bug causato da questo... e non è stato affatto divertente trovarlo!)

A si una cosa da stare attenti nel codice, vedo che nel tuo è presente questo errore, è assicurarsi che il puntatore che passi "viva abbastanza" per cui il thread ne abbia sempre accesso, voglio dire, te hai allocato array sullo stack, un allocazione sullo stack viene persa quando quella funzione va out of scope, ora potrebbe essere che la tua funzione vada out of scope prima che il thread abbia terminato il suo lavoro, nel tuo caso probabilmente non è così, in quanto il main dovrebbe andare out of scope per ultimo, ma nel caso di altre funzioni, bisogna starci attenti. Quindi direi che è altamente consigliato allocare i parametri da passare al thread sullo heap di modo da essere certi che questi non vadano mai out of scope prima che il thread abbia terminato, o alternativamente, fare un join con il thread prima che la variabile che si è passato vada out of scope, onde evitare bug difficili da scovare...
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [C] Cast void->int thread

Messaggio da vbextreme »

Per semplificarsi(?) la vita

Codice: Seleziona tutto

typedef void*(*thread_f)(void*);
#define thr_new(A,F,P) pthread_create (A, NULL, (thread_f)F,(void *)P)

void* miothread(int* vettore)
{...}

...
...
int array[10];
rc=thr_new(&mio_3d, miothread, array);
...
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Grazie @Ale4
A si una cosa da stare attenti nel codice, vedo che nel tuo è presente questo errore, è assicurarsi che il puntatore che passi "viva abbastanza" per cui il thread ne abbia sempre accesso, voglio dire, te hai allocato array sullo stack, un allocazione sullo stack viene persa quando quella funzione va out of scope, ora potrebbe essere che la tua funzione vada out of scope prima che il thread abbia terminato il suo lavoro, nel tuo caso probabilmente non è così, in quanto il main dovrebbe andare out of scope per ultimo, ma nel caso di altre funzioni, bisogna starci attenti.
Certo capisco. in teoria il main come dici tu dovrebbe essere l'ultimo a terminare.
logico che se l'array lo passo dal thread A a B e B lo elabora, se per qualsiasi motivo A termina prima ho problemi.
Credo che in quel caso si debba applicare una politica del tipo: B aspetta la terminazione di A, poi al limite termina anche tu (B)
Presumo si usi "pthread_join".
Per i cast, dico la verità, che non ci ho a che fare spesso, quindi mi devo un po' ripassare il materiale. Idem per i puntatori a funzione.
Li ho studiati, ma devo ripassare, personalmente non li uso spesso, per non dire mai.
Grazie anche a te @Vb
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Penso che un cast corretto possa essere così, ho ripassato un po':

Codice: Seleziona tutto

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>


    
void *f(void *x)
{
    printf("prova passaggio per indirizzo a 3d\n" );
    printf ("valore originale nel main di x=%d\n",*(int*)x);
    *(int*)x=100+*(int*)x;
    printf ("valore mofificato in f =%d\n",*(int*)x);
    pthread_exit (NULL);
}

int main(void)
{
    pthread_t mio_3d;
    int rc;
    int x=120;
    printf("Creo 3d\n");
    rc = pthread_create (&mio_3d, NULL, f,(void *)&x);
    if (rc!=0)
    {
        puts("ERRORE");
        exit(-1);
    }
    rc=pthread_join( mio_3d, NULL );// 0 return se ok
    /*if (rc==0)
    {
        puts("3d  terminato");
    }*/
    printf("valore x dopo 3d=%d\n",x);
    return 0;
}
Corretto?
Però il mio pc ha un core solo, quindi di fatto non potrò mai avere un vero parallelismo giusto?
Credo siano applicate delle procedure di scheduling (se non ricordo male il termine).
Ad ogni modo documentandomi un po' noto che i thread sono molto complessi se affrontati nei dettagli.
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Cast void->int thread

Messaggio da fabio massacci »

Penso che un cast corretto possa essere così
non sono su linux per cui non sono sicuro, ma mi pare tutto corretto
Però il mio pc ha un core solo, quindi di fatto non potrò mai avere un vero parallelismo giusto?
no, dipende da cosa hai effettivamente, se il tuo processore ha l'hypertheading comunque hai parallelismo (in parte anche hardware, con un grado che dipende da quanto nuovo sia il procio), quindi sfrutti il parallelismo comunque anche in quel caso...
certo che se hai un pentium 3 allora no non c'è nemmeno l'hyperthreading e non lo sfrutti, anche se potrebbe comunque avere in casi limitati un avanzamento delle performance perchè potrebbe riempire meglio la coda di istruzioni, ma in genere no

consiglio: dovresti studiarti anche il problema della sincronizzazione dell'accesso alle variabili condivise, il minimo indispensabile (che è poi l'approccio che anche io uso) è l'uso dei mutex
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Ciao Fabio :) io ho un AMD, dovrei vedere, ora non sono sul mio pc e non ricordo bene, guarderò.
consiglio: dovresti studiarti anche il problema della sincronizzazione dell'accesso alle variabili condivise, il minimo indispensabile (che è poi l'approccio che anche io uso) è l'uso dei mutex
I mutex ho letto nei vari pdf, ma calcola che sono agli inizi e non so bene ancora come muovermi e il tempo come al solito è risicato.
Mi piacerebbe iniziare a fare una prova stile giochi anni 80: non so far stampare una lettera a caso sul terminale che poi scompare dopo x tempo
e tu in un lasso di tempo massimo es 1 secondo devi scriverla. Se sbagli hai perso, se passa il secondo hai perso.
Credo che si possa fare con i thread, uno in background tiene il tempo, ecc... solo che non so bene come fare e non ho capito se devono comunicare
tra loro. Magari entrano in ballo anche i segnali, e anche li non ne so nulla...insomma di materiale ho visto che ce n'è.
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Cast void->int thread

Messaggio da fabio massacci »

io ho un AMD
se non è molto vecchio dovrebbe comunque beneficiare dei thread come performance, di sicuro per fare il giochino di cui parli i thread sono da usare per la natura del problema che cerca un parallelismo di funzionamento.

un modo al volo per implementarlo:

a) un thread A si avvia, entra in un loop che scrive su una variabile X una lettera ogni secondo, inoltre il loop finisce chiudendo il thread se un flag chiamato ad esempio 'close_threadA' vale 1
b) un altro thread B si avvia e entra in un loop che aspetta che l'utente scriva una lettera oppure scriva un numero per uscire dal loop (e quindi dal thread), quando l'utente scrive una lettera va a confrontarla con X (la variabile usata nel thread A), se sono uguali allora incrementa una variabile chiamata ad esempio 'count' per tenere traccia delle risposte esatte, se invece scrive un numero prima di uscire potrebbe settare close_threadA e close_threadC per segnalare anche al thread A e al thread C(vedi sotto) di chiudersi anche loro
c) un altro thread C si avvia e entra in un loop e legge in continuazione close_threadC per uscire, X e count per scrivere un messaggio tipo "lettera attuale: X numero lettere indovinate: count"

in questo esempio le variabili condivise tra i tre thread che devi gestire tramite mutex sono ovviamente X, count, close_threadA e close_threadC, non so se ci sono altri accorgimenti da tener presente visto che io di solito non uso input da tastiera ma mi pare che debba funzionare anche così, ti consiglio di accedere alle variabili condivise solo tramite funzioni get/set che usano il/i mutex:

Codice: Seleziona tutto

int get_count() {

    int ret;
    
    mutex.lock();
        ret = count;
    mutex.unlock();
    
    return ret;
}
la sintassi dei mutex al momento non la ricordo ma dovrebbe essere simile all'esempio (io in genere non uso posix direttamente e lavoro più in c++)
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Grazie Fabio.
Avevo intenzione di provare domani mattina, ma come al solito quei deficenti dei mie capi, mi comunicano solo ora che domani faccio giornata!!!
Comunque, grazie, appena posso provo a leggere bene.
per ora sto ancora approfondendo il passaggio di parametri e cercando i modi migliori di casting.
Mi sono anche soffermato su join per aspettare la terminazione di un 3d, credo sia un concetto importante.
A quanto pare allora anche per un giochino stupido come quello che ho proposto servono i mutex, giusto?
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Cast void->int thread

Messaggio da fabio massacci »

si certo, se due o più thread usano le stesse variabili devi regolarne l'accesso, almeno che tu non sia sicuro che non lavoreranno sulla stessa memoria contemporaneamente o almeno che non leggano tutti quanti (il problema infatti è se c'è qualcuno che scrive), attento anche ad alcune funzioni di libreria ad esempio mi è capitato di recente di scoprire (ma in realtà era evidente e dovevo aspettarmelo) che localtime() e affini non sono thread-safe, quindi o li usi con attorno un mutex o, se è possibile, usi le versioni thread-safe come ad esempio localtime_r(), altro esempio notevole, printf non è detto sia thread-safe anche se di solito lo è (dipende dall'implementazione del compilatore, comunque da quello che ho visto il c non lo garantisce), per quello nell'esempio ho pensato di far fare le scritture solo ad un thread per sicurezza (cosa che faccio spesso io stesso)
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [C] Cast void->int thread

Messaggio da vbextreme »

Anche malloc, non essendo una funzione rientrante, non è thread safe.
Per renderla tale va informato il compilatore con "-pthread".
La programmazione parallela offre molte insidie bisogna ponderare bene le proprie scelte altrimenti ci si ritrova ad avere 10 thread che alla fine lavorano in modo sequenziale causa un mutex o che finiscono in deadlock o in qualche altra strana diavoleria.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

@Vb mi ricordo un post dove dicevi che con thread ci sai fare.
Non è che magari posti degli esempi se ti va ?
Per esempio la situazione di mutex potrebbe essere la seguente?
Esempio : dichiaro un array in maniera globale, il primo thread s'impossessa dell'array per esempio lo inizializza a zero.
Il secondo 3d attende. Quando il primo ha finito "rilascia" l'array e il secondo entra in funzione, giusto?
Il concetto di mutex, ora che sono agli inizi, mi va in conflitto con join (aspetta).
Nel senso, lancio il 3d 1, aspetto, poi faccio il 2. Ma ripeto, sono confuso, ho studiato troppo poco, spero sabato di avere tempo mannaggia.
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Dovendo aspettare la fine di 2 thread nel main con join , ho notato che la cosa è sequenziale.
Nel senso se il thread 1 impiega più tempo del 2, nel main avrò la scritta: 3d2 terminato, solo quando il 3d1 1 è terminato:
Codice volante per prove:

Codice: Seleziona tutto

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>


   
void *PrintHello1(void *pid_3d)
{
  
    printf("sono 3d1\n");
    int i;
    double x;
    for (i=0 ; i<1000000; i++)
        x=(double)i;
    pthread_exit((void*) pid_3d);
     
}

void *PrintHello2(void *pid_3d)
{
    pthread_exit((void*) pid_3d);
}



int main(void)
{
    pthread_t tid_1;
    pthread_t tid_2;
    void *status;
    int rc;
    int rc1,rc2;
    int t=0;
    rc = pthread_create (&tid_1, NULL, PrintHello1, (void *)t);// 0 se ok
    if (rc!=0)
    {
        printf("ERROR; return code from pthread_create() is %d\n",rc);
        exit(-1);
    }
    t++;

    rc = pthread_create (&tid_2, NULL, PrintHello2, (void *)t);// 0 se ok
    if (rc!=0)
    {
        printf("ERROR; return code from pthread_create() is %d\n",rc);
        exit(-1);
    }

    rc1=pthread_join(pid_1,&status );// 0 return se ok
    if (rc1==0)
    {
        printf("3d1 %ld terminato\n",(long)status);
    }
       
    rc2=pthread_join(pid_2,&status );// 0 return se ok
    if (rc2==0)
    {
        printf("3d2 %ld terminato\n",(long)status);
    }
    return 0;
}

il thread 1 visto che deve elaborare, sarà sicuramente più lento del 2, ma nel main, ho messo prima il test join dell'1:

Codice: Seleziona tutto

rc1=pthread_join(pid_1,&status );// 0 return se ok
    if (rc1==0)
    {
        printf("3d1 %ld terminato\n",(long)status);
    }
       
    rc2=pthread_join(pid_2,&status );// 0 return se ok
    if (rc2==0)
    {
        printf("3d2 %ld terminato\n",(long)status);
    }
è possibile rilevare in modo indipendente nel main?
Cioè il main deve aspettare tutti e due, ma al tempo stesso rilevare quale ha terminato per primo.
ok, si potrebbe stampare nel thread stesso la fine, ma è un'altra cosa.
con programma in rete, mi pare faccia quello che voglio, non ne sono sicuro, ma ho notato che sfrutta gli attributi, che non ho ancora visto.
Grazie a chi mi da una mano :)
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: [C] Cast void->int thread

Messaggio da Claudio_F »

Fin qui mi sembra che funzioni tutto come in Python, quindi i concetti generali sono validi.

Si può fare a meno del join bloccante implementando una comunicazione tra main e thread (tramite variabili condivise o queue indipendenti). L' esempio con le variabili è più semplice (anche se ci saranno sistemi migliori): il main imposta le variabili (una per thread) a false, avvia i thread, e ciclicamente legge le variabili, quando sono true vuol dire che i processi hanno segnalato il loro termine.

I mutex/lock invece sono come i cartelli libero/occupato di un cesso pubblico, è evidente cosa succede se qualcuno si dimentica di girarli su occupato quando entra, o di rigirarli su libero quando esce.

Non c'entrano direttamente con join, nel senso che sono solo un modo per usare senza conflitti una risorsa condivisa tra i vari thread in esecuzione, mentre join è un modo per far attendere a un thread la fine di un altro (il main è il thread principale).
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Grazie Claudio, la mia domanda è un po' teorica nel senso che magari non avrò mai la necessità.
Comunque provo.
Per quanto riguarda i mutex, ci sto studiando, ma sono un po' confuso.
non ho capito bene alcuni concetti, ma ho davvero approfondito poco...tempo maledetto!!
EDIT:
Ma la protezione di variabili\dati condivise, ovvero mutex, non può essere banalmente risolta con dei flag?
Mi spiego e premetto che non voglio fare di testa mia, studierò i mutex, ma giusto per capire.
Esempio ho l'array X che deve essere elaborato dal thread 1 e 2. Ma prima, per forza di cose deve essere elaborato da 1, poi dal 2.
Se io dichiaro una variabile globale, come flag per esempio i, posta a 0, so che il thread 2 non potrà accedere all'array X fintanto che i
rimane a 0.
Quindi una volta finito il thread 1, pongo i a 1.
Quindi nel thread 2 tramite un if (i==1) fai quello che devi fare.
Non è la stessa cosa? Una sorta di stop, precedenza, chiamatelo come volete, il tutto con un semplice flag?
Ripeto, è solo per capire.
Interessante poi quello che ha detto Vbexetreme: bisogna stare attenti a creare molti 3d con mutex, ci si potrebbe imbottigliare in un sacco
di precedenze, andando di fatto così a perdere il parallelismo, ma svolgendo solo sequenzialmente molti 3d, di fatto come normalissime funzioni.
Spero che qualcuno mi sappia chiarire il discorso fatto sopra...a naso credo che sia una sorta di mutex, implementata un po' in modo
artigianale.
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Cast void->int thread

Messaggio da fabio massacci »

EDIT:
Ma la protezione di variabili\dati condivise, ovvero mutex, non può essere banalmente risolta con dei flag?
Mi spiego e premetto che non voglio fare di testa mia, studierò i mutex, ma giusto per capire.
Esempio ho l'array X che deve essere elaborato dal thread 1 e 2. Ma prima, per forza di cose deve essere elaborato da 1, poi dal 2.
Se io dichiaro una variabile globale, come flag per esempio i, posta a 0, so che il thread 2 non potrà accedere all'array X fintanto che i
rimane a 0.
Quindi una volta finito il thread 1, pongo i a 1.
Quindi nel thread 2 tramite un if (i==1) fai quello che devi fare.
Non è la stessa cosa? Una sorta di stop, precedenza, chiamatelo come volete, il tutto con un semplice flag?
Ripeto, è solo per capire.
Interessante poi quello che ha detto Vbexetreme: bisogna stare attenti a creare molti 3d con mutex, ci si potrebbe imbottigliare in un sacco
di precedenze, andando di fatto così a perdere il parallelismo, ma svolgendo solo sequenzialmente molti 3d, di fatto come normalissime funzioni.
Spero che qualcuno mi sappia chiarire il discorso fatto sopra...a naso credo che sia una sorta di mutex, implementata un po' in modo
artigianale.
per quel che riguarda i flag, in generale, NON puoi usarli in quanto chi ti garantisce che siano operazioni atomiche? La logica ti sembra la stessa perchè lo è solo che ti manca un dettaglio: settare un flag non è un operazione sola in generale, quindi se ad esempio stai settando un a variabile(flag) intera a 1 con un thread e un altro thread cerca di leggerle quella variabile può darsi che il primo scriva solo metà della variabile prima che il secondo abbia finito di leggerla, così che il valore letto dal secondo non è corretto! Insomma i flag si usano per sincronizzare i thread ma solo insieme ai mutex, questo perchè i mutex garantiscono che siano presi in possesso solo da un thread per volta (non so come, non mi sono mai interessato).
Detto questo comunque, tanto per fare folklore, c'è da dire che su alcune piattaforme effettivamente le operazioni di base sui tipi di base sono garantite atomiche e infatti su alcuni sistemi operativi (RTOS) i mutex li ho visti implementati tramite il settaggio di flag (se non ricordo male un esempio è su pic32 con compilatore xc32)
Riguardo invece all'esempio che hai ipotizzato, se hai solo due thread e il secondo deve aspettare per forza l'altro direi che stai perdendo tempo perchè le due operazioni sono sequenziali quindi tanto vale scrivere un programma normale che le svolge sequenzialmente ! Diverso invece se hai ad esempio il thread 1 che prepare svariati buffer e li manda a svariati thread secondari che agiscono in parallelo ognuno sul proprio buffer(tra l'altro in questo caso i thread secondari potrebbero essere lanciati dal thread 1)
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Riguardo invece all'esempio che hai ipotizzato, se hai solo due thread e il secondo deve aspettare per forza l'altro direi che stai perdendo tempo perchè le due operazioni sono sequenziali quindi tanto vale scrivere un programma normale che le svolge sequenzialmente
hai perfettamente ragione :D ho realizzato oggi mentre mi rompevo al lavoro...pensavo: "...mi sa che ho postato una cazzata... :D "
E..però se si usano i mutex, dovrai aspettare qualcosa, quindi ricado nella sequenzialità...
porca miseria, devo trovare del buon materiale su cui studiare, o un bell'esempio di mutex.
intanto grazie Fabio
fabio massacci
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 289
Iscrizione: mercoledì 11 giugno 2014, 14:12
Desktop: Lubuntu
Distribuzione: Ubuntu 20.04.3 LTS

Re: [C] Cast void->int thread

Messaggio da fabio massacci »

adesso sono su windows quindi non posso provarlo o correggerlo, ho riscritto un po' il tuo esempio, magari ha degli errori ma almeno nella sostanza dovrebbe aiutarti:

Codice: Seleziona tutto

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

//----------------------------------------------------------------------- 
                        
pthread_mutex_t shut_down_request_mutex;
char shut_down_request;

char GetShutDownRequest() {
    char ret;
    
    pthread_mutex_lock( &shut_down_request_mutex );
        ret = shut_down_request; 
    pthread_mutex_unlock( &shut_down_request_mutex );
    
    return ret;
}
 
void SetShutDownRequest( char _val ) {
    pthread_mutex_lock( &shut_down_request_mutex );
    shut_down_request = _val; 
    pthread_mutex_unlock( &shut_down_request_mutex );
}

//-----------------------------------------------------------------------

pthread_mutex_t print_mutex;

void secure_print( char* _param ) {
    pthread_mutex_lock( &print_mutex );
        printf( "sono 3d %s\n", etichetta );      
    pthread_mutex_unlock( &print_mutex );
}  

//-----------------------------------------------------------------------  
 
void *PrintHello1(void *_nome)
{
    char* etichetta = (char*)_nome;
    
    while( GetShutDownRequest() == 0 ) {
        secure_print( etichetta );            
        usleep(100000);
    }
    
    pthread_exit((void*) _nome);         
}

   
void *PrintHello2(void *_nome)
{
    char* etichetta = (char*)_nome;
    
    while( GetShutDownRequest() == 0 ) {
        secure_print( etichetta );           
        usleep(100000);
    }
    
    pthread_exit((void*) _nome);         
}

//-----------------------------------------------------------------------

int main(void)
{
    pthread_t tid_1;
    pthread_t tid_2;
    void *status;       
    
    int rc;
    int rc1,rc2;
    char nome_thread1[] = "bau";
    char nome_thread2[] = "miao";
    
    /////////////////// INIT MUTEX E VARIABILI CONDIVISE
    if( pthread_mutex_init(&shut_down_request_mutex, NULL) != 0 )
    {
        printf("\n shut_down_request_mutex init failed\n");
        exit(-1);
    }
    SetShutDownRequest(0);//qui non sarebbe necessario perchè i thread ancora non sono partiti
    
    if( pthread_mutex_init(&print_mutex, NULL) != 0 )
    {
        printf("\n print_mutex init failed\n");
        exit(-1);
    }
    
    /////////////////// CREAZIONE THREAD
    rc = pthread_create (&tid_1, NULL, PrintHello1, (void *)nome_thread1);// 0 se ok
    if (rc!=0)
    {
        printf("ERROR; return code from pthread_create() is %d\n",rc);
        exit(-1);
    }
    codice++;

    rc = pthread_create (&tid_2, NULL, PrintHello2, (void *)nome_thread1);// 0 se ok
    if (rc!=0)
    {
        printf("ERROR; return code from pthread_create() is %d\n",rc);
        exit(-1);
    }

    ////////////////// ATTENDI PER UN PO'
    sleep( 5 );//facciamo lavorare i thread in parallelo per circa 5 secondi
    for( i=0; i<5; i++ ) {
        secure_print( "MAIN" );
        sleep(1);
    }
    SetShutDownRequest( 1 );//richiediamo ai thread di chiudersi (non ci dovrebbero mettere molto)
    

    ////////////////// ATTENDI CHE I THREAD SIANO COMPLETAMENTE CHIUSI 
    ////////////////// (NON è DEL TUTTO NECESSARIO IN QUESTO CASO, 
    ////////////////// è PER USCIRE PIù PULITO)
    rc1=pthread_join(pid_1,&status );// 0 return se ok
    if (rc1==0)
    {
        printf("3d1 %s terminato\n",(char*)status);
    }
       
    rc2=pthread_join(pid_2,&status );// 0 return se ok
    if (rc2==0)
    {
        printf("3d2 %s terminato\n",(char*)status);
    }
    return 0;
}

ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: [C] Cast void->int thread

Messaggio da ixamit »

gila75 ha scritto: E..però se si usano i mutex, dovrai aspettare qualcosa, quindi ricado nella sequenzialità...
porca miseria, devo trovare del buon materiale su cui studiare, o un bell'esempio di mutex.
Mi aggrego e restando sull'idea del produttore/consumatore/i, con e senza mutua esclusione, ti allego un esempio per poterci smanettare un po'.
Prova a cambiare questa parte, o altro se preferisci, e verificarne l'andamento

Codice: Seleziona tutto

#define MUTEX 0                    /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_CONSUMER 24        /* CONSUMER THREADS to be created */
#define MAX_ITER 100               /* ITERATION FOR PRODUCER */
#define MAX_ARR  10                /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)   
#define PAUSE_CONSUMER usleep(400)

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h> /* usleep */

#define MUTEX 0                    /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_CONSUMER 24        /* CONSUMER THREADS to be created */
#define MAX_ITER 100               /* ITERATION FOR PRODUCER */
#define MAX_ARR  10                /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)   
#define PAUSE_CONSUMER usleep(400)


struct coda
{
    char buf[MAX_ARR][8];
    int nmemb,back,front;
    char finish;
    pthread_mutex_t mutex;
};

#if !MUTEX
#define pthread_mutex_lock(x) ;
#define pthread_mutex_unlock(x) ;
#endif

void *producer (void *args)
{
    struct coda *coda = args;
    int n = 1;


    while (n<=MAX_ITER)
    {
        pthread_mutex_lock(&coda->mutex);
        if (coda->nmemb < MAX_ARR)
        {
            snprintf(&coda->buf[coda->back][0],8,"0x%02X",n);
            printf ("add %s (ndx=%d) \n",
                    coda->buf[coda->back],coda->back);
            coda->back=(coda->back+1)%MAX_ARR;
            coda->nmemb++;
            n++;
        }
        pthread_mutex_unlock(&coda->mutex);
        PAUSE_PRODUCER;
    }

    pthread_mutex_lock(&coda->mutex);
    coda->finish=1;
    pthread_mutex_unlock(&coda->mutex);

    pthread_exit (NULL);
}

void *consumer (void *args)
{
    struct coda *coda=args;

    while(1)
    {
        pthread_mutex_lock(&coda->mutex);

        if (coda->finish && coda->nmemb<=0) 
        {
            pthread_mutex_unlock(&coda->mutex);
            break;
        }
        if (coda->nmemb>0)
        {
            printf ("del %s (ndx=%d id=%lu nmemb=%d)\n",
                coda->buf[coda->front],coda->front,
                pthread_self(),coda->nmemb);
            coda->front=(coda->front+1)%MAX_ARR;
            coda->nmemb--;
        }
        pthread_mutex_unlock(&coda->mutex);
        PAUSE_CONSUMER;
    }
    pthread_exit (NULL);
}

int main ()
{
    static struct coda coda;
    pthread_t tp,tc[NTHREAD_CONSUMER];
    int i;

    if (pthread_mutex_init(&coda.mutex, NULL) != 0)
        { perror("mutex_ init");return -1; }


    printf ("MUTEX is %s\n",MUTEX?"ENABLE":"DISABLE");
    printf ("Adding %d members to %d elements queue\n",MAX_ITER,MAX_ARR);
    
    coda.finish=0;

    /* create single producer */
    if ((pthread_create (&tp, NULL, producer,&coda)))
        {perror ("thread_create");return -1;}

    /* create N consumer */
    for (i=0;i<NTHREAD_CONSUMER;i++)
        if ((pthread_create (&tc[i], NULL, consumer,&coda)))
            {perror ("thread_create");return -1;}

    for (i=0;i<NTHREAD_CONSUMER;i++)
        pthread_join(tc[i], NULL );
    pthread_join(tp, NULL );

    return 0;
}
Esistono anche altre funzioni utili in questi contesti, tipo le condizioni:

Codice: Seleziona tutto

pthread_cond_wait(&condp, &the_mutex); /* wait  producer */
...
pthread_cond_signal(&condc);        /* wake up consumer */
Trovi qualche buon esempio e qualche dettaglio in https://docs.oracle.com/cd/E19455-01/80 ... index.html

edit:
corretto codice sopra: n = 1 nella funzione producer

Altra versione per N producer

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h> /* usleep */

#define MUTEX 1                    /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_PRODUCER 24        /* PRODUCER THREADS to be created */
#define NTHREAD_CONSUMER 24        /* CONSUMER THREADS to be created */
#define MAX_ITER 100               /* ITERATION FOR PRODUCER */
#define MAX_ARR  10                /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)   
#define PAUSE_CONSUMER usleep(0)


struct data
{
    char buf[MAX_ARR][8]; /* queue */
    int nmemb,back,front;  
    char finish; /* bool true/false */
    int n; /* producer counter */
    pthread_mutex_t mutex;
};

#if !MUTEX
#define pthread_mutex_lock(x) ;
#define pthread_mutex_unlock(x) ;
#define pthread_mutex_destroy(x) ;
#endif

#define PRINT(x,ndx) \
    printf ("%s %s (tid=%lu ndx=%d nmemb=%d)\n",x,data->buf[ndx],pthread_self(),ndx,data->nmemb);

void *producer (void *args)
{
    struct data *data = args;

    while (1)
    {
        pthread_mutex_lock(&data->mutex);
        if (data->n > MAX_ITER)
        {
            pthread_mutex_unlock(&data->mutex);
            break;
        } 
        if (data->nmemb < MAX_ARR)
        {
            snprintf(&data->buf[data->back][0],8,"0x%02X",data->n);

            PRINT("add",data->back);

            data->back=(data->back+1)%MAX_ARR;
            data->nmemb++;
            data->n++;
        }
        pthread_mutex_unlock(&data->mutex);
        PAUSE_PRODUCER;
    }

    pthread_mutex_lock(&data->mutex);
    data->finish=1;
    pthread_mutex_unlock(&data->mutex);

    pthread_exit (NULL);
}

void *consumer (void *args)
{
    struct data *data=args;

    while(1)
    {
        pthread_mutex_lock(&data->mutex);

        if (data->finish && data->nmemb<=0) 
        {
            pthread_mutex_unlock(&data->mutex);
            break;
        }
        if (data->nmemb>0)
        {
            PRINT("\tdel",data->front);

            data->front=(data->front+1)%MAX_ARR;
            data->nmemb--;
        }
        pthread_mutex_unlock(&data->mutex);
        PAUSE_CONSUMER;
    }
    pthread_exit (NULL);
}

int main ()
{
    static struct data data;
    pthread_t tp[NTHREAD_PRODUCER],tc[NTHREAD_CONSUMER];
    int i;

    if (pthread_mutex_init(&data.mutex, NULL) != 0)
        { perror("mutex_ init");return -1; }


    printf ("MUTEX is %s\n",MUTEX?"ENABLE":"DISABLE");
    printf ("Adding %d members to %d elements queue\n",MAX_ITER,MAX_ARR);

    data.n=1;

    /* create single producer */
    for (i=0;i<NTHREAD_PRODUCER;i++)
        if ((pthread_create (&tp[i], NULL, producer,&data)))
            {perror ("thread_create");return -1;}

    /* create N consumer */
    for (i=0;i<NTHREAD_CONSUMER;i++)
        if ((pthread_create (&tc[i], NULL, consumer,&data)))
            {perror ("thread_create");return -1;}

    for (i=0;i<NTHREAD_CONSUMER;i++)
        pthread_join(tc[i], NULL );
    for (i=0;i<NTHREAD_PRODUCER;i++)
        pthread_join(tp[i], NULL );

    pthread_mutex_destroy(&data.mutex);

    return 0;
}

gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: [C] Cast void->int thread

Messaggio da gila75 »

Grazie ragazzi, scusate se rispondo solo ora...periodo incasinato.
Appena riesco provo i vostri esempi :)
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 3 ospiti