yhirose / cpp-httplib

A C++ header-only HTTP/HTTPS server and client library
MIT License
13.13k stars 2.31k forks source link

multithreading information #1598

Closed questor closed 1 year ago

questor commented 1 year ago

Hi! It would help to get some more information what needs to be protected by multithread syncronization, need handlers accessing shared datastructures all syncronization between different handlers working in parallel? From the current documentation it seems so, I think stating it clearly in the documentation would help to prevent hard-to-find errors of multiple threads using data structures without syncronization.

yhirose commented 1 year ago

Thanks for the suggestion! Are you talking about potential issues when using a client object in more than one thread, right?

questor commented 1 year ago

yeah, exactly this usecase needs to be protected to not create data races and other "funny" things..

yhirose commented 1 year ago

When it comes to calling request methods like send, Get, Put, ... in more than one thread simultaneously, it's safe because those method calls will be serialized in order with mutex objects (std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_) and std::lock_guard<std::mutex> guard(socket_mutex_). (That means that we can't really send more than one HTTP request at the same time with the same socket. It's because we are not able to share the same TCP socket for more than one request technically.)

https://github.com/yhirose/cpp-httplib/blob/bd9612b81e6f39ab24a4be52fcda93658c0ca2dc/httplib.h#L6384-L6386 https://github.com/yhirose/cpp-httplib/blob/bd9612b81e6f39ab24a4be52fcda93658c0ca2dc/httplib.h#L6396 https://github.com/yhirose/cpp-httplib/blob/bd9612b81e6f39ab24a4be52fcda93658c0ca2dc/httplib.h#L6457

Does it make sense?

questor commented 1 year ago

Do I understand you right that the following can NOT happen: I have a webserver using your libraries with two different Get-Endpoints defined taking 10seconds to process the requests. Now when two different clients connect and both execute one Get-Request that both requests will be processed in parallel?

I would assume both request will be handled by two different worker-threads and by that are processed in parallel and are NOT serialized via a mutex by the httplib? And that would mean that handlers using common datastructures need to be made thread-safe (even the same handler in the usecase that the same handler is called by different clients in parallel?). So the syncronization really needs to be done in the usercode handling the requests? No?

Really simple example: ComplexDatastructure data; svr.Get("/hi", [](const Request & /req/, Response &res) { data.process(req); // <-- this needs to be protected because it might be called from different threads? res.set_content("Hello World!\n", "text/plain"); });

yhirose commented 1 year ago

I was only talking about the client side. If a web server supports HTTP Keep-Alive, we sometimes encounter situations that may cause the thread-safe issue in http::Client.

Case 1

auto t1 = std::thread([]() { httplib::Client cli("...").Get("/hi", [](auto&, auto&) { ... }); };
auto t2 = std::thread([]() { httplib::Client cli("...").Get("/hi", [](auto&, auto&) { ... }); };

In this case, we don't have any thread issue, since each request is handled with a separate socket.

Case 2

httplib::Client cli("...");
auto t1 = std::thread([&]() { cli.Get("/hi", [](auto&, auto&) { ... }) };
auto t2 = std::thread([&]() { cli.Get("/hi", [](auto&, auto&) { ... }) };

In this case, if the web server accepts Keep-Alive requests, two calls may access the same socket simultaneously. But, a TCP socket doesn't handle more than one request at the same time and those requests should be serialized. That's why the client needs to protect the underlying socket from such simultaneous access.

Your example is talking about the server. It's not safe of course, since the handler gets called per each request. You shouldn't store content from a request handler in such a 'global' or shared variable.

Hope it helps!

questor commented 1 year ago

thanks for the clarification and thanks for your great library, it helps me a lot in my development work!