2013-05-19 12 views
5

W wielowątkowym programie Linux używanym do komunikacji szeregowej, czy jest możliwe (i jakie byłoby najlepsze podejście), aby zakończyć blokowanie wywołania read() z innego wątku?Linux, anuluj blokowanie read()

Chciałbym, aby wszystko było jak najbardziej reaktywne i unikaj wykorzystania limitów czasu z wielokrotnym odpytywaniem.

Tłem tego pytania jest to, że próbuję utworzyć bibliotekę komunikacji szeregowej Scala dla systemu Linux przy użyciu JNI. Staram się, aby strona natywna była tak prosta, jak to tylko możliwe, zapewniając między innymi funkcję read() i close(). Po stronie Scala jeden wątek wywoływał funkcję read() i blokował do momentu udostępnienia danych z portu szeregowego. Jednak port szeregowy można zamknąć za pomocą innych środków, powodując wywołanie close(). Teraz, aby zwolnić zablokowany wątek, musiałbym jakoś anulować wywołanie systemowe.

+0

Powiązane: https://stackoverflow.com/questions/384391/how-to-signal-select-to-return-immediately –

Odpowiedz

7

Jedna dość popularna sztuczka: zamiast blokowania w read() blokuj w select() na twoim gnieździe szeregowym i potoku. Następnie, gdy inny wątek chce obudzić twój wątek, może to zrobić, pisząc bajt na drugim końcu tej rury. Ten bajt spowoduje, że select() wróci, a twój wątek może teraz oczyszczać i kończyć, lub cokolwiek musi zrobić. (Zauważ, że aby to działało w 100% niezawodnie, prawdopodobnie będziesz chciał ustawić twój port szeregowy jako nieblokujący, aby upewnić się, że twój wątek blokuje tylko w select() i nigdy nie jest czytany())

+1

oddelegowany. Wykonuję prawie wszystkie moje programy wielowątkowe w ten sposób. Jest to wzorzec wprost z Komunikacyjnych Procesów Sekwencyjnych (CSP). Biorąc pod uwagę, że Scala nie komunikuje obiektów Scala (praktyczna implementacja CSP), myślę, że sugestia jest bardzo odpowiednia. BTW największą wadą programowania dla Windows Win32 lub .NET jest to, że nie można wybrać() na rurach, masowego zaniedbania. MS chciałoby, żebyś myślał, że asynchroniczne IO jest lepsze, ale prowadzi do naprawdę niechlujnego kodu. Projekt Cygwin miał problemy z pisaniem select(). Ich rozwiązanie wiąże się z wieloma wątkami i sondowaniem. – bazza

+0

FWIW możesz zrobić tę samą sztuczkę (tylko 10 razy wysiłek;)) pod Windows, tworząc dwa gniazda TCP i łącząc() jeden z nich z drugim, jak pokazano tutaj: http://code.google.com /p/imagesoft/source/browse/trunk/rpcrt4/socketpair.c?r=5 –

+1

Dzięki za odpowiedź! Select nie działał dla mnie (może zrobiłem coś nie tak), jednak podczas czytania stron man (select) natknąłem się na poll(). To działało idealnie :) –

4

Sygnały AFAIK to jedyny sposób na przerwanie dowolnego wątku z blokującego wywołania systemowego.

Użyj celu pthread_kill() wycelowanego w gwint z sygnałem USR1.

+0

Dzięki za odpowiedź, ale pthread_kill nie byłoby możliwe w moim przypadku użycia (ponieważ funkcje są wywoływane z różne wątki JVM). Czy są jakieś obejścia, których mogę użyć? Słyszałem trochę o epolu, ale moje testy też nie działały. –

+0

Nie wiem wystarczająco dużo o JNI, aby złożyć rekomendację. Możesz użyć 'epoll' z jednego wątku i' close() 'z innego, ale uważam, że jest to niezdefiniowane zachowanie. – kja