Domanda

Sto cercando di condividere una struttura tra due thread che non è una variabile globale. La variabile stessa viene istanziata nello stack nella funzione principale, quindi il suo puntatore viene passato come parametro a entrambi i thread all'avvio di entrambi i thread.

Quello che sto scoprendo è che quando cambio il valore di un membro di quella struttura quel cambiamento non si riflette mai nell'altro pthread. C'è un modo per condividere una variabile non globale (ad esempio un numero intero) tra due thread, in modo tale che le modifiche apportate a quella variabile in un thread vengano visualizzate nell'altro?

Questo è tutto perché voglio evitare di aggiungere variabili globali per la manutenibilità del codice.

È stato utile?

Soluzione

Ricorda che i thread ottengono il loro stack - quindi se passi un numero intero e la funzione non rientra nell'ambito, ti riferisci alla memoria che ora contiene qualcosa di completamente diverso.

void foo(void)
{
    pthread_t t1, t2;
    struct foo common_value;

    if (pthread_create(&t1, NULL, a, &common_value) != 0)
    {
        return -1;
    }    

    if (pthread_create(&t2, NULL, b, &common_value) != 0)
    {
        return -1;
    }    

    // upon exiting this function, common_value is no longer what you think it is!
}

Altri suggerimenti

Non pretendo di eleganza, ma questo sembra funzionare per me su MacOS X 10.5.8.

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

static void *writer(void *arg)
{
    int * volatile i = arg;

    for (*i = 1; *i < 10; (*i)++)
    {
        printf("writer(): pseudo_global = %d\n", *i);
        fflush(stdout);
        sleep(1);
    }
    printf("writer(): pseudo_global = %d (exiting)\n", *i);
    fflush(stdout);
    return(0);
}

static void *reader(void *arg)
{
    int * volatile i = arg;
    while (*i < 10)
    {
        printf("reader(): pseudo_global = %d\n", *i);
        fflush(stdout);
        sleep(1);
    }
    printf("reader(): pseudo_global = %d (exiting)\n", *i);
    fflush(stdout);
    exit(0);
}

int main(void)
{
    volatile int pseudo_global = 0;
    pthread_t t1;
    pthread_t t2;
    if (pthread_create(&t1, 0, writer, &pseudo_global) != 0)
    {
        perror("pthread_create() for thread 1");
        exit(1);
    }
    if (pthread_create(&t2, 0, reader, &pseudo_global) != 0)
    {
        perror("pthread_create() for thread 1");
        exit(1);
    }
    while (pseudo_global < 10)
    {
        printf("main():   pseudo_global = %d\n", pseudo_global);
        fflush(stdout);
        sleep(1);
    }
    printf("main():   pseudo_global = %d (exiting)\n", pseudo_global);
    fflush(stdout);
    return(0);
}

Nota che ho inserito il qualificatore "volatile" nel codice per "accertarmene", ma a parte il richiamo di avvisi sui qualificatori scartati nelle chiamate a pthread_create () , non ha prodotto alcun differenza significativa. Ho anche eseguito il codice senza alcun volatile senza problemi.

Questo codice dimostra, credo, che su almeno un'implementazione di thread POSIX, puoi effettivamente condividere una variabile locale nello stack di una funzione che non è uscita mentre i thread sono in esecuzione.

Sono disposto a credere che dovrei stare più attento alla terminazione del thread e assicurarmi che main () non esca senza usare pthread_join () per garantire che i thread sono usciti per primi.

Esempio di output:

$ make ptex
gcc -O ptex.c -o ptex  
ptex.c: In function ‘main’:
ptex.c:40: warning: passing argument 4 of ‘pthread_create’ discards qualifiers from pointer target type
ptex.c:45: warning: passing argument 4 of ‘pthread_create’ discards qualifiers from pointer target type
$ ./ptex
writer(): pseudo_global = 1
main():   pseudo_global = 0
reader(): pseudo_global = 1
writer(): pseudo_global = 2
main():   pseudo_global = 2
reader(): pseudo_global = 2
writer(): pseudo_global = 3
main():   pseudo_global = 3
reader(): pseudo_global = 3
writer(): pseudo_global = 4
main():   pseudo_global = 4
reader(): pseudo_global = 4
writer(): pseudo_global = 5
reader(): pseudo_global = 5
main():   pseudo_global = 5
writer(): pseudo_global = 6
reader(): pseudo_global = 6
main():   pseudo_global = 6
writer(): pseudo_global = 7
reader(): pseudo_global = 7
main():   pseudo_global = 7
writer(): pseudo_global = 8
reader(): pseudo_global = 8
main():   pseudo_global = 8
writer(): pseudo_global = 9
reader(): pseudo_global = 9
main():   pseudo_global = 9
writer(): pseudo_global = 10 (exiting)
reader(): pseudo_global = 10 (exiting)
main():   pseudo_global = 10 (exiting)
$

Stai facendo la cosa giusta, ma la tua esperienza suggerisce che stai sbagliando. Prova a spostarlo in una variabile globale e vedi se continui a non provare la condivisione.

Dopo aver verificato che pubblica un semplice codice di esempio che illustra il tuo problema che altri possono testare.

A mio avviso, condividere una variabile stack è peggio che avere una variabile globale. Almeno avrei allocato un po 'di memoria sull'heap da condividere tra i thread. Se la memoria è destinata a vivere per tutta la durata del programma, non devi nemmeno preoccuparti di liberarlo e il thread principale può tornare immediatamente. Con la variabile stack, devi assicurarti di non far apparire prematuramente il frame dello stack in cui si trova la variabile.

Detto questo, penso che usare un globale sia in realtà la soluzione migliore. Inserisci il globale in un file separato e dichiaralo statico in modo che sia solo globale per il file. Quindi, inserisci solo le funzioni del thread in quel file in modo che solo loro abbiano accesso alla variabile. Mi piace di più poiché rende esplicito che la memoria è condivisa dai thread. L'argomento di pthread_create è davvero pensato per essere un contesto specifico del thread, e non sarà necessariamente chiaro guardando le funzioni del thread che a tutti i thread viene passato lo stesso puntatore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top