Server w C++ z wykorzystaniem wątków


..czyli jak nie zablokować się podczas oczekiwania na zdarzenie

Standardowa linuksowa komunikacja miedzy klientem, a server opiera się w najprostszym przypadku na użyciu blokujących funkcji takich jak ::recv() lub ::accept(). Ograniczenie się tylko do możliwości obsługi jednego klienta jest jednak delikatnie mówiąc wysoce nieefektywne. Z pomoca przychodzi tutaj stary dobry linuksowy fork (ukłon w stronę języka C) lub thready (C++, a zwłaszcza Cpp11 i nowsze)

Wspomniane std::thread są przejrztste i wygodne w użyciu, jednak nie można zapominać, że to tylko ustandaryzwana nakładkana na "pthread" (w przypadku gcc kompilujemy dodając flagę "-lpthread"). W przypadku naszego serwera, zgodnie z klasycznym podejściem bedziemy czekali na pojawienie się połączenia klienckiego, a gdy to nastąpi - przekierujemy je do nowego wątku i wrócimy do oczekiwania na kolejnego klienta. Bardzo wygodne w tej sytuacji jest skorzystanie z wzorca projektowego pula obiektów. W tym miejscu moge polecić gotową bibliotekę ThreadPool.

Pierwsze linijki powyższego kodu to eleganckie,silnie typowane "constexpr", zamiast dawnego "#define". Określiają numer portu servera (klient musi go znać, by móc się połączyć) i ilość predefiniowanych threadów (w tymwypadku możemy jednocześnie obsługiwać 16 klientów). Na serwerze uruchomiony został broker z mojej własnej biblioteki Hqtt. Kooryduje on komunikację w modelu "publisher/subscriber" (pełny kod jak zwykle na github). Nastepnie tworzona jest pula wątków, które bedą przypisywane do obsługi żadań każdego z klientów po zaakceptowaniu połączenia. Alternatywnie zamiast do obsługi wątku zamiast funkcji można użyć wyrażenia lambda, jak w poniższym przykładzie.

W tym wypadku nie ma potrzeby przekazywania jawnie brokera jako paramteru, można przechwycić referencje do niego ([&]).

TAGS: c++, wzorce projektowe,