Domanda

Sto scrivendo un'applicazione che blocca l'input da due istreams .

La lettura da entrambi istream è una chiamata sincrona (bloccante), quindi ho deciso di creare due Boost :: thread per fare la lettura.

Ognuno di questi thread può arrivare a " end " (basato su alcuni input ricevuti), e una volta che " fine " viene raggiunto, entrambi i flussi di input interrompono la ricezione. Sfortunatamente, non posso sapere chi lo farà.

Pertanto, non posso join () su entrambi i thread, poiché solo un thread (non può essere predeterminato quale) restituirà effettivamente (sblocco).

Devo in qualche modo forzare l'altro a uscire, ma è bloccato in attesa di input, quindi non può decidere da solo che è il momento di tornare (variabili di condizione o cosa no).

È un modo per entrambi:

  • Invia un segnale a boost :: thread o
  • Forza un istream su " fail " ;, oppure
  • Kill a Boost :: thread?

Nota:

  • Uno dei istreams è cin
  • Sto cercando di riavviare il processo, quindi non riesco a chiudere i flussi di input in un modo che proibisca il loro ripristino.

Modifica:

  • So quando " fine " viene raggiunto e so quale thread è stato completato correttamente e quali devono essere eliminati. È l'omicidio che devo capire (o una strategia diversa per leggere da un istream).
  • Ho bisogno di entrambi i thread per uscire e pulire correttamente :(

Grazie!

È stato utile?

Soluzione

Non penso che ci sia un modo per farlo su più piattaforme, ma pthread_cancel dovrebbe essere quello che stai cercando. Con un thread boost puoi ottenere native_handle da un thread e chiama pthread_cancel su di esso.

Inoltre, un modo migliore potrebbe essere quello di utilizzare la spinta asio equivalente di una chiamata selezionata su più file. In questo modo un thread verrà bloccato in attesa dell'input, ma potrebbe provenire da entrambi i flussi di input. Non so quanto sia facile fare qualcosa di simile con iostreams però.

Altri suggerimenti

Sì, c'è!

boost :: thread :: terminate () farà il lavoro secondo le tue specifiche.

Provocherà un'eccezione al thread target. Supponendo che non sia rilevato, lo stack si svolgerà correttamente distruggendo tutte le risorse e terminando l'esecuzione del thread.

La risoluzione non è istantanea. (Il thread sbagliato è in esecuzione in quel momento, comunque.)

Succede in condizioni predefinite - il più conveniente per te sarebbe probabilmente quando chiami boost :: this_thread :: sleep (); , che potresti fare periodicamente fare quel thread.

Se un thread boost sta bloccando un'operazione di i / o (ad es. cin > > qualunque cosa ), boost :: thread :: terminate () non ucciderà il filo. cin i / o non è un punto di terminazione valido. Cattura 22.

Bene su Linux, uso pthread_signal (SIGUSR1), poiché interrompe il blocco dell'IO. Non esiste una chiamata su Windows come ho scoperto durante il porting del mio codice. Solo uno deprecato nella chiamata di lettura socket. In Windows devi definire esplicitamente un evento che interromperà la tua chiamata di blocco. Quindi non esiste una cosa (AFAIK) come un modo generico per interrompere il blocco di IO.

Il design boost.thread gestisce ciò gestendo punti di interruzione ben identificati. Non conosco bene boost.asio e sembra che tu non voglia fare affidamento su di esso comunque. Se non si desidera fare il refactor per usare il paradigma non bloccante, quello che si può fare è usare qualcosa tra non-blocking (polling) e blocco IO. Cioè fare qualcosa del tipo (pseudo codice?):

while(!stopped && !interrupted)
{
    io.blockingCall(timeout);
    if(!stopped && !interrupted)
    {
        doSomething();
    }
}

Quindi interrompi i tuoi due thread e li unisci ...

Forse è più semplice nel tuo caso? Se hai un thread principale che sa che un thread è terminato, devi solo chiudere l'IO dell'altro thread?

Modifica: A proposito, sono interessato alla soluzione finale che hai ...

Anch'io ho avuto un problema simile e ho raggiunto questa soluzione, che alcuni altri lettori di questa domanda potrebbero trovare utili:

Supponendo che si stia utilizzando una variabile di condizione con un comando wait (), è importante sapere che in Boost l'istruzione wait () è un punto di interruzione naturale. Quindi basta inserire un blocco try / catch attorno al codice con l'istruzione wait e consentire alla funzione di terminare normalmente nel blocco catch.

Ora, supponendo che tu abbia un contenitore con i tuoi puntatori di thread, fai scorrere i puntatori di thread e chiama interrupt () su ogni thread, seguito da join ().

Ora tutti i thread termineranno in modo corretto e qualsiasi pulizia della memoria relativa a Boost dovrebbe funzionare in modo pulito.

Invece di provare a uccidere il tuo thread, puoi sempre provare a unirti al thread e, se fallisce, ti unisci all'altro. (Supponendo che sarai sempre in grado di unirti ad almeno uno dei tuoi due thread).

In boost: thread stai cercando funzione timed_join .

Se si desidera cercare la risposta corretta, tuttavia, sarebbe utilizzare io non bloccante con le attese a tempo. Consentendo di ottenere la struttura del flusso di io sincrono, con il non-blocco di io asincrono.

Parli della lettura da un istream, ma un istream è solo un'interfaccia. per stdin, puoi semplicemente chiudere il descrittore di file stdin per interrompere la lettura. Per quanto riguarda l'altro, dipende da dove stai leggendo ...

Sembra che i thread non ti stiano aiutando a fare ciò che vuoi in modo semplice. Se Boost.Asio non è di tuo gradimento, considera l'utilizzo di select () .

L'idea è di ottenere due descrittori di file e utilizzare select () per dirti quale di essi ha input disponibile. Il descrittore di file per cin è in genere STDIN_FILENO ; come ottenere l'altro dipende dai tuoi dettagli (se è un file, basta open () invece di usare ifstream ).

Chiama select () in un ciclo per scoprire quale input leggere e quando vuoi fermarti, basta uscire dal loop.

In Windows, utilizzare QueueUserAPC per mettere in coda un proc che genera un'eccezione. Questo approccio funziona bene per me.

TUTTAVIA : ho appena scoperto che aumentare i mutex ecc. non sono "modificabili". su win32, quindi QueueUserAPC non può interromperli.

Molto tardi, ma in Windows (ed è precursori come VMS o RSX per quelli che ricordano tali cose) userò qualcosa come ReadFileEx con una routine di completamento che segnala quando finito, e CancelIO se la lettura deve essere annullata in anticipo .

Linux / BSD ha un'API sottostante completamente diversa che non è così flessibile. L'uso di pthread_kill per inviare un segnale funziona per me, ciò interromperà l'operazione di lettura / apertura.

Vale la pena implementare diversi codici in quest'area per ciascuna piattaforma, IMHO.

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