2011-10-31 11 views
20

Creo un thread e lo metto in un loop infinito. Ottengo perdite di memoria durante il controllo del codice con valgrind. Ecco il mio codice:Come posso uccidere un pthread che si trova in un loop infinito, dall'esterno di quel loop?

#include <pthread.h> 
#include <time.h> 

void thread_do(void){ 
    while(1){} 
} 

int main(){ 
    pthread_t th; 
    pthread_create(&th, NULL, (void *)thread_do, NULL); 

    sleep(2); 
    /* I want to kill thread here */ 
    sleep(2); 
    return 0; 
} 

Quindi un thread viene creato in main e viene eseguito solo thread_do() tutto il tempo. C'è un modo per ucciderlo dall'interno principale dopo 2 secondi? Ho provato sia pthread_detach(th) e pthread_cancel(th) ma ho ancora perdite.

+3

L'annullamento di pthreads indica che il thread non ha la possibilità di pulire la memoria allocata. –

+2

Ok, ho risolto questo problema avendo solo un 'keepalive = 1' globale. Quindi ho cambiato 'while (1)' in 'while (keepalive)'. Per uccidere il thread ora devo solo cambiare il valore della variabile keepalive a 0 e voilà! – Pithikos

risposta

32

Come @sarnold ha sottolineato, per impostazione predefinita il thread non può essere cancellato con pthread_cancel() senza chiamare le funzioni che sono i punti di cancellazione ... ma questo può essere modificato utilizzando pthread_setcanceltype() per impostare il tipo di annullamento del thread su asincrono anziché differito. Per fare ciò, aggiungere qualcosa come pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); all'inizio della funzione thread, prima di iniziare il ciclo. Potresti quindi interrompere la discussione chiamando pthread_cancel(th) da main().

Nota, tuttavia, che la cancellazione dei thread in questo modo (sia asincrona o meno) non elimina le risorse allocate nella funzione thread (come notato da Kevin in un commento). Per fare questo in modo pulito, è possibile:

  • Assicurarsi che il filo non fa nulla di cui ha bisogno per ripulire prima di uscire (ad esempio utilizzando malloc() di allocare un buffer)
  • Assicurarsi di avere qualche modo di pulizia dopo il thread altrove, dopo che il thread è terminato
  • Utilizzare pthread_cleanup_push() e pthread_cleanup_pop() per aggiungere i gestori di pulitura per eliminare le risorse quando il thread viene annullato. Si noti che questo è ancora rischioso se il tipo di cancellazione è asincrono, poiché il thread potrebbe essere annullato tra l'allocazione di una risorsa e l'aggiunta del gestore di cleanup.
  • Evitare l'uso di pthread_cancel() e fare in modo che il thread controlli alcune condizioni per determinare quando terminare (che verrebbe controllato in cicli di esecuzione prolungata). Poiché il thread verifica la terminazione stessa, può eseguire qualsiasi operazione di pulizia necessaria dopo il controllo.

Un modo di attuare l'ultima opzione è quella di utilizzare un mutex come flag, e prova con pthread_mutex_trylock() avvolto in una funzione da utilizzare nelle prove ciclo:

#include <pthread.h> 
#include <unistd.h> 
#include <errno.h> 

/* Returns 1 (true) if the mutex is unlocked, which is the 
* thread's signal to terminate. 
*/ 
int needQuit(pthread_mutex_t *mtx) 
{ 
    switch(pthread_mutex_trylock(mtx)) { 
    case 0: /* if we got the lock, unlock and return 1 (true) */ 
     pthread_mutex_unlock(mtx); 
     return 1; 
    case EBUSY: /* return 0 (false) if the mutex was locked */ 
     return 0; 
    } 
    return 1; 
} 

/* Thread function, containing a loop that's infinite except that it checks for 
* termination with needQuit() 
*/ 
void *thread_do(void *arg) 
{ 
    pthread_mutex_t *mx = arg; 
    while(!needQuit(mx)) {} 
    return NULL; 
} 

int main(int argc, char *argv[]) 
{ 
    pthread_t th; 
    pthread_mutex_t mxq; /* mutex used as quit flag */ 

    /* init and lock the mutex before creating the thread. As long as the 
    mutex stays locked, the thread should keep running. A pointer to the 
    mutex is passed as the argument to the thread function. */ 
    pthread_mutex_init(&mxq,NULL); 
    pthread_mutex_lock(&mxq); 
    pthread_create(&th,NULL,thread_do,&mxq); 

    sleep(2); 

    /* unlock mxq to tell the thread to terminate, then join the thread */ 
    pthread_mutex_unlock(&mxq); 
    pthread_join(th,NULL); 

    sleep(2); 
    return 0; 
} 

Se il filo non è distaccato (generalmente non predefinito), è necessario chiamare pthread_join() dopo aver arrestato il thread.Se il thread è staccato, non è necessario unirsi a esso, ma non si sa esattamente quando termina (o anche approssimativamente, a meno che non si aggiunga un altro modo per indicare la sua uscita).

+0

per utilizzare questa soluzione mutex per multiple pthread Avrei bisogno di un mutex per thread, giusto? consigliereste questa soluzione in questo caso? –

+2

@RicardoCrudo No, solo un mutex ... se 'needQuit()' lo blocca con successo, lo sblocca subito dopo ... solo 'main()' mantiene il mutex per un lungo periodo di tempo. Qualsiasi thread che usi 'needQuit()' per controllare se uscire si chiuderà quando nessun altro ha il mutex bloccato, e lo bloccherà solo per un momento (molto molto breve). Solo una chiamata 'needQuit()' avrà successo alla volta, ma ogni thread riceverà comunque una chiamata una dopo l'altra. – Dmitri

5

Alcuni piccoli pensieri:

  1. Stai cercando di cancellare il tuo thread, ma se le condizioni di cancellazione in atto è per una cancellazione differita, il tuo thread_do() non sarà mai cancellata, perché non chiama mai alcun funzioni che sono i punti di cancellazione:

    A thread's cancellation type, determined by 
    pthread_setcanceltype(3), may be either asynchronous or 
    deferred (the default for new threads). Asynchronous 
    cancelability means that the thread can be canceled at any 
    time (usually immediately, but the system does not guarantee 
    this). Deferred cancelability means that cancellation will 
    be delayed until the thread next calls a function that is a 
    cancellation point. A list of functions that are or may be 
    cancellation points is provided in pthreads(7). 
    
  2. non sta unendo il filo nel codice semplice esempio; chiamare pthread_join(3) prima della fine del programma:

    After a canceled thread has terminated, a join with that 
    thread using pthread_join(3) obtains PTHREAD_CANCELED as the 
    thread's exit status. (Joining with a thread is the only way 
    to know that cancellation has completed.)