Chlorek Temat założony przez niniejszego użytkownika |
[C++, boost::asio] Zakończenie pracy acceptora i wyjście z wątku » 2014-05-03 17:37:21 Korzystam z biblioteki Asio (w wersji Boost). Mój problem polega na tym, że chcę w trakcie pracy aplikacji serwera zakończyć jego działanie. Przed tym zrobiłem już cały clean-up wszelkich połączonych klientów itd. i pozostało jedynie wyjście z wątku serwera. Na przeszkodzie stoi accept() oczekujący na kolejne połączenia do serwera. Jak wyczytałem acceptor nie jest thread-safe, a MUSZĘ go wyłączyć w jakiś sposób z innego wątku.
Wiem, że powinienem użyć w tym wypadku schematu non-blocking, ale po pierwsze mam już wszystko napisane (musiałbym zrobić rewrite sporej części programu a to odpada, bo i tak zbyt wiele czasu już na ten projekt poświęciłem) a po drugie blocking jest w pełni wystarczający (nie potrzebuję non-blocking do niczego innego jak właśnie zakończenie acceptora). |
|
DejaVu |
» 2014-05-03 17:47:03 Accept przestanie blokować połączenia, jeżeli wywołasz disconnecta na sockecie. |
|
Chlorek Temat założony przez niniejszego użytkownika |
» 2014-05-03 17:58:08 @DejaVu Nie bardzo rozumiem co masz na myśli. Socket nie jest połączony, dopiero accept() "przypisuje" mu połączenie. Wywołanie na nim metody close(), gdy nie ma żadnego połączenia nic nie zmienia. while( true ) { socket_ptr sock( new tcp::socket( io_service ) ); acceptor.accept( * sock ); ... ... ...
To tak okrojony ile się da kod który mam. Wątek stoi na accept(), chcę by nie czekał na połączenie i poszedł dalej (zmusić go muszę z innego wątku). #Edit Jako, że zdarzyć się to ma na koniec programu (jego wyłączeniu) może być dowolna metoda na zabicie wątku, która nie spowoduje mi memory leak'ów. Jakieś pomysły? Jak wydać sygnał zabicia wątku z innego? Wykorzystuję std::thread. |
|
DejaVu |
» 2014-05-03 21:53:12 Zapodaj właściwy fragment implementacji. Socket TCP przestaje być blokującym jeżeli serwer zamknie nasłuchiwanie portu. |
|
Chlorek Temat założony przez niniejszego użytkownika |
» 2014-05-03 22:45:18 @DejaVu Nie różni się to wiele, ale skoro potrzebne to proszę, mam nadzieję, że ten kod wystarczy: asio::io_service io_service; tcp::acceptor acceptor = tcp::acceptor( io_service, tcp::endpoint( tcp::v4(), port ) );
while( true ) { socket_ptr sock( new tcp::socket( io_service ) ); acceptor.accept( * sock ); }
Co ja mam zrobić z tym socketem? Wciąż nie do końca rozumiem co masz na myśli, gdyż przez nasłuchiwanie rozumiem w tym przypadku acceptor.accept(*sock) . Jak zamknąć nasłuchiwanie? A co ważniejsze jak zrobić to w sposób bezpieczny dla wielu wątków? Jeśli aktualnie nasłuchuję na jakimś sockecie to chyba ryzykowne jest wprowadzanie do niego zmian (w ogóle) a co dopiero z innego wątku? |
|
DejaVu |
» 2014-05-04 00:50:05 Powinieneś mieć spoza wątku dostęp do acceptor po to, aby wywołać na nim acceptor.close() . Pętla while wówczas powinna wyglądać tak: while( acceptor.is_open() ) { }
Przy kończeniu pracy z aplikacją, poprawnym politycznie jest zamknięcie acceptor-a. Zamknięcie acceptora spowoduje odblokowanie czekającej metody acceptor.accept() . To z kolei spowoduje odblokowanie pętli while, która zakończy się, ponieważ acceptor będzie już zamknięty. |
|
Chlorek Temat założony przez niniejszego użytkownika |
» 2014-05-04 19:36:39 Niestety nie do końca to działa jak powinno. Mianowicie gdy wywołam z innego wątku close() na acceptorze to otrzymuję wyjątek: accept: Parametr jest niepoprawny
Co prawda tym samym uciekam z pętli, ale to rozwiązanie nie wygląda najlepiej. |
|
DejaVu |
» 2014-05-04 20:08:22 No to obsłuż wyjątek, skoro ta klasa rzuca wyjątkiem w chwili wystąpienia błędu. Poza tym może socket tworzy Ci się null-owy, skoro dostałeś wyjątek o niepoprawnej wartości przekazanej do argumentu metody. |
|
« 1 » 2 |