Synchronous client request calls is now safe to use concurrently
This commit is contained in:
parent
9b5063f422
commit
fd764d908c
4 changed files with 56 additions and 7 deletions
|
|
@ -181,7 +181,8 @@ namespace SimpleWeb {
|
||||||
std::shared_ptr<asio::io_service> io_service;
|
std::shared_ptr<asio::io_service> io_service;
|
||||||
|
|
||||||
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
||||||
/// If reusing the io_service for other tasks, please use the asynchronous request functions instead.
|
/// If reusing the io_service for other tasks, use the asynchronous request functions instead.
|
||||||
|
/// Do not use concurrently with the asynchronous request functions.
|
||||||
std::shared_ptr<Response> request(const std::string &method, const std::string &path = std::string("/"),
|
std::shared_ptr<Response> request(const std::string &method, const std::string &path = std::string("/"),
|
||||||
string_view content = "", const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
string_view content = "", const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||||
std::shared_ptr<Response> response;
|
std::shared_ptr<Response> response;
|
||||||
|
|
@ -191,14 +192,23 @@ namespace SimpleWeb {
|
||||||
throw system_error(ec);
|
throw system_error(ec);
|
||||||
});
|
});
|
||||||
|
|
||||||
io_service->reset();
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(concurrent_synchronous_requests_mutex);
|
||||||
|
++concurrent_synchronous_requests;
|
||||||
|
}
|
||||||
io_service->run();
|
io_service->run();
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(concurrent_synchronous_requests_mutex);
|
||||||
|
if(--concurrent_synchronous_requests == 0)
|
||||||
|
io_service->reset();
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
||||||
/// If reusing the io_service for other tasks, please use the asynchronous request functions instead.
|
/// If reusing the io_service for other tasks, use the asynchronous request functions instead.
|
||||||
|
/// Do not use concurrently with the asynchronous request functions.
|
||||||
std::shared_ptr<Response> request(const std::string &method, const std::string &path, std::istream &content,
|
std::shared_ptr<Response> request(const std::string &method, const std::string &path, std::istream &content,
|
||||||
const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||||
std::shared_ptr<Response> response;
|
std::shared_ptr<Response> response;
|
||||||
|
|
@ -208,13 +218,22 @@ namespace SimpleWeb {
|
||||||
throw system_error(ec);
|
throw system_error(ec);
|
||||||
});
|
});
|
||||||
|
|
||||||
io_service->reset();
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(concurrent_synchronous_requests_mutex);
|
||||||
|
++concurrent_synchronous_requests;
|
||||||
|
}
|
||||||
io_service->run();
|
io_service->run();
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(concurrent_synchronous_requests_mutex);
|
||||||
|
if(--concurrent_synchronous_requests == 0)
|
||||||
|
io_service->reset();
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
|
/// Do not use concurrently with the synchronous request functions.
|
||||||
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
|
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
|
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
|
||||||
auto session = std::make_shared<Session>(this, get_connection(), create_request_header(method, path, header));
|
auto session = std::make_shared<Session>(this, get_connection(), create_request_header(method, path, header));
|
||||||
|
|
@ -256,6 +275,7 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
|
/// Do not use concurrently with the synchronous request functions.
|
||||||
void request(const std::string &method, const std::string &path, string_view content,
|
void request(const std::string &method, const std::string &path, string_view content,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) {
|
||||||
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
||||||
|
|
@ -353,6 +373,9 @@ namespace SimpleWeb {
|
||||||
std::shared_ptr<bool> cancel_callbacks;
|
std::shared_ptr<bool> cancel_callbacks;
|
||||||
std::shared_ptr<SharedMutex> cancel_callbacks_mutex;
|
std::shared_ptr<SharedMutex> cancel_callbacks_mutex;
|
||||||
|
|
||||||
|
size_t concurrent_synchronous_requests = 0;
|
||||||
|
std::mutex concurrent_synchronous_requests_mutex;
|
||||||
|
|
||||||
ClientBase(const std::string &host_port, unsigned short default_port) : io_service(new asio::io_service()), cancel_callbacks(new bool(false)), cancel_callbacks_mutex(new SharedMutex()) {
|
ClientBase(const std::string &host_port, unsigned short default_port) : io_service(new asio::io_service()), cancel_callbacks(new bool(false)), cancel_callbacks_mutex(new SharedMutex()) {
|
||||||
auto parsed_host_port = parse_host_port(host_port, default_port);
|
auto parsed_host_port = parse_host_port(host_port, default_port);
|
||||||
host = parsed_host_port.first;
|
host = parsed_host_port.first;
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,6 @@ int main() {
|
||||||
if(!ec)
|
if(!ec)
|
||||||
cout << response->content.rdbuf() << endl;
|
cout << response->content.rdbuf() << endl;
|
||||||
});
|
});
|
||||||
client.io_service->reset(); // needed because the io_service has been run already in the synchronous examples
|
|
||||||
client.io_service->run();
|
client.io_service->run();
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,6 @@ int main() {
|
||||||
if(!ec)
|
if(!ec)
|
||||||
cout << response->content.rdbuf() << endl;
|
cout << response->content.rdbuf() << endl;
|
||||||
});
|
});
|
||||||
client.io_service->reset(); // needed because the io_service has been run already in the synchronous examples
|
|
||||||
client.io_service->run();
|
client.io_service->run();
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ int main() {
|
||||||
assert(call);
|
assert(call);
|
||||||
|
|
||||||
{
|
{
|
||||||
vector<int> calls(100);
|
vector<int> calls(100, 0);
|
||||||
vector<thread> threads;
|
vector<thread> threads;
|
||||||
for(size_t c = 0; c < 100; ++c) {
|
for(size_t c = 0; c < 100; ++c) {
|
||||||
calls[c] = 0;
|
calls[c] = 0;
|
||||||
|
|
@ -263,6 +263,34 @@ int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test concurrent synchronous request calls
|
||||||
|
{
|
||||||
|
HttpClient client("localhost:8080");
|
||||||
|
{
|
||||||
|
vector<int> calls(100, 0);
|
||||||
|
vector<thread> threads;
|
||||||
|
for(size_t c = 0; c < 100; ++c) {
|
||||||
|
calls[c] = 0;
|
||||||
|
threads.emplace_back([c, &client, &calls] {
|
||||||
|
try {
|
||||||
|
auto r = client.request("GET", "/match/123");
|
||||||
|
assert(SimpleWeb::status_code(r->status_code) == SimpleWeb::StatusCode::success_ok);
|
||||||
|
assert(r->content.string() == "123");
|
||||||
|
calls[c] = 1;
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for(auto &thread : threads)
|
||||||
|
thread.join();
|
||||||
|
assert(client.connections.size() == 1);
|
||||||
|
for(auto call : calls)
|
||||||
|
assert(call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
HttpClient client("localhost:8080");
|
HttpClient client("localhost:8080");
|
||||||
assert(client.connections.size() == 0);
|
assert(client.connections.size() == 0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue