2008-11-07 15 views
20

Piszę aplikację, która blokuje dane wejściowe z dwóch istreams.Zabij zablokowane Zwiększenie :: Wątek

Czytanie z istream jest wywoływaniem synchronicznym (blokującym), więc postanowiłem utworzyć dwa Boost::thread s, aby wykonać odczyt.

Każdy z tych wątków może dostać się do "końca" (w zależności od odebranego wejścia), a po osiągnięciu "końca" oba strumienie wejściowe przestają odbierać. Niestety, nie wiem, co to zrobi.

Tak więc, nie mogę join() na obu wątków, ponieważ tylko jeden wątek (nie może być określony z góry) rzeczywiście powróci (odblokować).

Muszę jakoś zmusić drugą do wyjścia, ale jest zablokowana, czekając na wejście, więc sama nie może zdecydować, że nadszedł czas na powrót (zmienne warunkowe lub co nie).

jest ich sposób albo:

  • wysłać sygnał impuls :: wątek lub
  • wymusić istream na "nie", lub
  • Zabić boost :: wątek?

Uwaga:

  • Jednym z istreams jest cin
  • próbuję ponownie uruchomić proces, więc nie mogę zamknąć strumienie wejściowe w taki sposób, że zabrania im resetowanie.

Edit:

  • wiem, kiedy zostanie osiągnięty „koniec”, a ja wiem, który wątek został pomyślnie zakończone, a które musi być zabity. To zabójstwo, którego potrzebuję, aby dojść do porozumienia (lub inną strategię czytania z istream).
  • muszę oba wątki, aby wyjść i oczyszczanie prawidłowo :(

Dzięki!

Odpowiedz

4

Nie sądzę, istnieje sposób, aby zrobić to przekrój platformę, ale pthread_cancel powinno być to, czego szukasz Za pomocą wątku doładowania możesz uzyskać native_handle z wątku i wywołać na nim pthread_cancel

Ponadto lepszym sposobem może być użycie boostu asio, odpowiednika wybrania połączenia na wielu plikach. być zablokowanym, czekając na dane wejściowe, ale może pochodzić z dowolnej ze znaków wejściowych eam. Nie wiem, jak łatwo jest zrobić coś takiego z iostreams.

+0

Na szczęście pracuję dla maszyny na Linuksa, ale wolę wersję przenośną. Dzięki za to! – mmocny

+0

pthread_cancel() nie robi tego dla mnie w podobnym scenariuszu, nawet nie ustawiając jego typu anulowania na ASYNCHRONOUS. – gatopeich

0

Zamiast próbować zabić twój wątek, możesz zawsze spróbować dołączyć do wątku, a jeśli się nie powiedzie, zamiast tego dołączysz do drugiego. (Zakładając, że zawsze będziesz mógł dołączyć co najmniej jeden z twoich dwóch wątków).

W boost: wątek, którego szukasz do funkcji timed_join.

Jeśli jednak chcesz spojrzeć na poprawną odpowiedź, skorzystaj z opcji nieblokującej io przy taktowaniu. Umożliwienie uzyskania struktury przepływu synchronicznego io, z nieblokującym asynchronicznym układem io.

Mówisz o czytaniu z formularza, ale istream jest tylko interfejsem. dla stdin, możesz po prostu fclose deskryptor pliku stdin, aby przerwać czytanie. Jeśli chodzi o inne, to zależy od tego, gdzie czytasz ...

+0

Wszelkie sugestie, jak to zrobić? Miałem wrażenie, że to niemożliwe (aby to zrobić) z cin. I już wspomniałem, że przyłączam się do jednego wątku prawidłowo, to drugi, z którym muszę się uporać. W każdym razie dzięki. – mmocny

+0

Jeszcze raz dziękuję. Ale myślę, że nie rozumiesz tego pytania. Jeden z wątków nigdy się nie przyłącza(). Wiem, jak uzyskać jeden z wątków do przyłączenia się i zidentyfikować ten, który nie ma. Potrzebuję odblokować drugi wątek. (lub wymyślić inne rozwiązanie) – mmocny

0

Pod Windows, użyj QueueUserAPC do kolejki proc, który zgłasza wyjątek. To podejście działa dobrze dla mnie.

JEDNAK: Właśnie znalazł które zwiększają muteksy etc nie są „alertable” na win32, więc QueueUserAPC nie może ich przerwać.

1

Cóż, na Linuksie używam pthread_signal (SIGUSR1), ponieważ przerywa blokowanie IO. Nie ma takiego wywołania w oknach, jakie odkryłem podczas przenoszenia mojego kodu. Tylko jeden wycofany w wywołaniu odczytu gniazda. W oknach należy jawnie zdefiniować zdarzenie, które przerwie połączenie blokujące. Tak więc nie ma czegoś takiego (AFAIK) jako ogólnego sposobu przerwania blokowania IO.

Konstrukcja boost.thread obsługuje to poprzez zarządzanie dobrze zidentyfikowanymi punktami przerwania. Nie znam boost.asio i wydaje się, że i tak nie chcesz na nim polegać. Jeśli nie chcesz, aby refaktor używał paradygmatu nieblokującego, możesz użyć czegoś między blokowaniem (odpytywaniem) a blokowaniem IO. To jest coś jak (pseudo kod):

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

Następnie przerwać swoje dwa wątki i połączyć je ...

Być może łatwiej jest w Twoim przypadku? Jeśli masz wątek główny, który wie, że jeden wątek został zakończony, musisz zamknąć IO innego wątku?

Edit: Nawiasem mówiąc jestem zainteresowany w końcowym roztworze masz ...

0

Wydaje się, że wątki nie pomagają robisz, co chcesz w prosty sposób. Jeśli Boost.Asio nie odpowiada Twoim potrzebom, rozważ użycie opcji select().

Chodzi o to, aby uzyskać dwa deskryptory plików i użyć select(), aby powiedzieć, które z nich ma dostępne dane wejściowe. Deskryptor pliku dla cin jest zwykle STDIN_FILENO; jak uzyskać drugi zależy od twoich szczegółów (jeśli jest to plik, tylko open() to zamiast używać ifstream).

Zadzwoń pod select() w pętli, aby dowiedzieć się, które wejście przeczytać, a kiedy chcesz się zatrzymać, po prostu zerwij pętlę.

4

Tak, jest!

boost::thread::terminate() wykona zadanie zgodnie ze specyfikacją.

Spowoduje to, że docelowy wątek wyrzuci wyjątek. Zakładając, że jest nieprzechwycony, stos rozwinie się właściwie niszcząc wszystkie zasoby i kończąc wykonywanie wątków.

Wypowiedzenie nie jest natychmiastowe. (W każdym razie niewłaściwy wątek działa w tym momencie.)

Zdarza się to w określonych warunkach - najwygodniej będzie dla ciebie, gdy zadzwonisz pod numer boost::this_thread::sleep();, który możesz okresowo wykonywać dla tego wątku.

+0

O czym ty mówisz? __boost__ nie ma takiej funkcji 'boost :: thread :: terminate()'. –

+1

Witam, @YagamyLight. Nie jestem pewien, czy naprawdę chcesz odpowiedzi, ale możesz napisać pytanie dotyczące tego, co stało się z 'boost :: thread :: endate' po napisaniu tej odpowiedzi. –

4

Jeśli wątek zwiększający ładunek blokuje operację i/o (np. cin>>whatever), boost::thread::terminate() nie zabije wątku. cin i/o nie jest prawidłowym punktem zakończenia. Złap 22.

1

miałem podobny problem siebie i osiągnęły to rozwiązanie, które niektórzy inni czytelnicy to pytanie może się przydać:

Zakładając, że używasz zmiennej stanie z polecenia wait(), to jest ważne, aby wiedzieć, że w Boost, instrukcja wait() jest naturalnym punktem przerwania. Więc po prostu wstaw kod try/catch dookoła kodu za pomocą instrukcji wait i pozwól, aby funkcja kończyła się normalnie w twoim bloku catch.

Teraz, zakładając, że masz pojemnik ze wskaźnikami nici, wykonaj iteracje nad wskaźnikami wątku i wywołaj przerwanie() w każdym wątku, a następnie join().

Teraz wszystkie twoje wątki zakończą się z gracją, a każde usuwanie pamięci związane z Boostem powinno działać poprawnie.

0

Bardzo późno, ale w Windows (i jego prekursorów, takich jak VMS lub RSX dla tych, którzy pamiętają takie rzeczy) użyłbym czegoś takiego jak ReadFileEx z procedurą zakończenia, która sygnalizuje po zakończeniu, i CancelIO, jeśli odczyt musi zostać anulowany wcześnie.

Linux/BSD ma zupełnie inny bazowy interfejs API, który nie jest tak elastyczny. Używanie pthread_kill do wysłania sygnału działa dla mnie, co zatrzyma operację odczytu/otwarcia.

Warto zaimplementować inny kod w tym obszarze dla każdej platformy, IMHO.