2010-08-20 3 views
6

Ho un pthread in attesa su una variabile di condizione che utilizza pthread_cond_wait. È in attesa di dati da una struttura di coda riempita da un altro thread. Voglio uccidere questo thread, preferibilmente senza pthread_kill. Su Linux e WinPthreads facendo un pthread_cancel(); pthread_join() è sufficiente per ucciderlo. Tuttavia, su OS X si blocca sulla chiamata pthread_join. Eventuali suggerimenti?Killing un pthread in attesa su una variabile di condizione

+0

Sto usando SDL quindi forse questo confonde il problema. So che SDL fornisce la sua implementazione di thread e forse dovrei usarlo perché pthread/SDL hanno alcune interazioni bizzarre, ma ho già un bel po 'di codice pthread scritto e preferirei mantenerlo in quel modo. – CarbonAsh

risposta

6

È possibile accedere alla coda e controllare lo schema dell'oggetto per gli elementi in coda? In tal caso, definire un tipo di oggetto coda che, in caso di accodamento, indica al thread che sta elaborando l'elemento di uscire con garbo.

Ora, a chiudere tali fili, semplicemente inviare un certo numero di questi "smettere" oggetti al HEAD della coda che corrisponde al numero di fili che effettuano interventi di coda, e si uniscono sui filetti.

Questo sembra molto più pulito rispetto alla "opzione nucleare" di pthread_cancel/kill.

+0

Questo è esattamente ciò che ho fatto! Grazie per il suggerimento, in questo modo il mio thread può ancora rimanere al buio ed eseguire in istanze non thread e la mia coda che è già thread aware può occuparsi del lavoro sporco e chiamare pthread_exit per uccidere il thread. – CarbonAsh

0

La prima cosa che vorrei provare sarebbe quella di calciare il variabile di condizione tra la cancellazione e il join, e hanno il controllo di thread di destinazione per la cancellazione in modo esplicito dopo ritorna dalla condizione di attesa.

Ecco perché il thread non risponde alla cancellazione mentre è nella condizione di attesa (o del tutto).

POSIX.1c-2004 (v6) afferma:

Lo stato cancelability e il tipo di eventuali discussioni recenti, compreso filetto in cui main() è stato prima invocato, sono rispettivamente PTHREAD_CANCEL_ENABLE e PTHREAD_CANCEL_DEFERRED.

Ciò significa che è necessario verificare esplicitamente la cancellazione con pthread_testcancel().

L'altra opzione è quella di impostare in realtà i fili si annullano tipo di PTHREAD_CANCEL_ASYNCHRONOUS quando inizia prima a correre, qualcosa di simile a:

int junk; 
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &junk); 
std::cout 
    << ((junk==PTHREAD_CANCEL_DEFERRED) ? "Was deferred" : "Wasn't") 
    << std::endl; 

Questo è, naturalmente, partendo dal presupposto che è quello il problema. Dovresti essere in grado di testare se sta esaminando l'output di quella terza riga sopra.

cancellazione è una richiesta al filo bersaglio che è libero di ignorare se lo desidera, al contrario di gran lunga più maligno pthread_kill(). Sono un grande sostenitore nel lasciare che i thread controllino la loro vita da quando l'ho trovato porta invariabilmente a un minor numero di problemi di concorrenza.

parte: Infatti, dopo essere stati acquistati in primissime edizioni di pthreads, prima ancora che l'integrazione in DCE, ho ancora trovo semplicemente utilizzando una variabile globale per ogni thread che indica quando dovrebbe uscire, insieme ai calci di mutex o alle variabili di condizione per riattivare i thread. Credo che dovrei aggiornare i miei metodi (o lo farei se potessi vedere un chiaro vantaggio). :-)

+0

Bene, preferirei sicuramente avere un metodo non-cancel ma ho il thread che si cancella non è in realtà consapevole del fatto che è in esecuzione in un thread. Ho provato a segnalare la variabile di condizione, ma poi legge dalla coda e segfaults perché non c'è nulla in esso. Mentre questo ha il comportamento desiderato di uscire dal programma, sembra "semplicemente sbagliato". – CarbonAsh

+0

BTW, non dovresti mai presumere che, solo perché tu torni da cond_wait, c'è lavoro disponibile. È possibile che due thread attendono di essere svegliati, il primo per ottenere il lavoro e il secondo non dovrebbe rilevare il lavoro disponibile e tornare ad aspettare. – paxdiablo

+1

Lo stato di cancellazione posticipata non significa che devi verificare esplicitamente la cancellazione con 'pthread_testcancel()'; questa funzione è solo uno dei molti punti di annullamento definiti da POSIX. Praticamente * non * desidera l'annullamento asincrono tranne quando si eseguono lunghi calcoli numerici con chiamate * no * di libreria di sorta. L'unica chiamata alla libreria che puoi effettuare mentre è abilitata la cancellazione asincrona consiste nel disabilitare la cancellazione asincrona. :-) –

6

pthread_cancel deve riattivare un filo che viene bloccato in pthread_cond_wait --- questo è uno dei punti di cancellazione richiesti. Se non funziona, allora qualcosa non va.

La prima cosa da verificare è che la cancellazione è effettivamente abilitata sul thread di destinazione --- chiamare esplicitamente pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&oldstate) sul thread di destinazione per essere sicuri. Se ciò non funziona, la cancellazione viene interrotta sulla tua piattaforma e dovrai ricorrere a alternative quali l'impostazione di un flag "please stop now" e la segnalazione della variabile di condizione.

Non utilizzare cancellazione asincrona a meno che non davvero sapere cosa si sta facendo --- può innescare l'annullamento nel mezzo di qualsiasi operazione (ad esempionel mezzo dell'impostazione di una funzione stack stack di chiamate o esecuzione di un distruttore), e quindi può lasciare il codice in uno stato completamente incoerente. La scrittura di codice asincrono-cancellabile è rigido.

Per inciso pthread_kill fa non uccidere un thread --- invia un segnale ad esso.

+0

Ho fatto pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, e oldstate). Il vecchio stato era PTHREAD_CANCEL_ENABLE e ciò non ha avuto alcun effetto. Sarei molto sorpreso se il pthreads di Mac OS X fosse rotto, ma non sono sicuro di cos'altro potrebbe essere sbagliato, in quanto questo codice funziona sia su windows che su Linux. – CarbonAsh

+0

pthreads funziona bene, ho scritto un piccolo programma: pthread_cond_t cond; pthread_mutex_t lock; void * tmain (void *) { pthread_mutex_lock (&lock); pthread_cond_wait (e cond, &lock); pthread_mutex_unlock (&lock); } int main() filetto { pthread_t; pthread_cond_init (e cond, NULL); pthread_mutex_init (& lock, NULL); pthread_create (e filetto, NULL, tmain, NULL); sleep (1); pthread_cancel (filo); pthread_join (filetto, NULL); } Per testarlo e esce dopo un secondo. Devo avere qualche altro bug nel mio codice. – CarbonAsh