Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++, boost::asio] Zakończenie pracy acceptora i wyjście z wątku

Ostatnio zmodyfikowano 2014-05-04 20:16
Autor Wiadomość
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).
P-109190
DejaVu
» 2014-05-03 17:47:03
Accept przestanie blokować połączenia, jeżeli wywołasz disconnecta na sockecie.
P-109191
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.
C/C++
while( true )
{
    // socket_ptr to shared_ptr do tcp::socket
    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.
P-109194
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.
P-109226
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:
C/C++
asio::io_service io_service;
tcp::acceptor acceptor = tcp::acceptor( io_service, tcp::endpoint( tcp::v4(), port ) );

// jakieś śmieci

while( true )
{
    socket_ptr sock( new tcp::socket( io_service ) );
    acceptor.accept( * sock );
   
    // więcej śmieci...
}

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?
P-109235
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:
C/C++
while( acceptor.is_open() )
{
    // (...)tu reszta Twojego kodu
}
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.
P-109245
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.
P-109305
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.
P-109308
« 1 » 2
  Strona 1 z 2 Następna strona