-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Closed
Description
When destroying an httplib::Client
object in one thread while a Get
request is still active in another thread, the program aborts with an assertion error, even after calling httplib::Client::stop()
.
My use case involves a thread consuming SSE using Get
. I want to stop the Get
request gracefully so the thread can exit. However, calling stop()
before destroying the client does not resolve the issue.
Assertion error:
client: httplib.h:7514: void httplib::ClientImpl::close_socket(Socket&): Assertion `socket_requests_in_flight_ == 0 || socket_requests_are_from_thread_ == std::this_thread::get_id()' failed.
Aborted (core dumped)
Tested on 2b5d1eea8d7e9f881ac4be04ce31df782b26b6a9
Minimal Reproduction:
client.cpp
#include "httplib.h"
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
using namespace httplib;
using namespace std;
int main(void) {
std::unique_ptr<Client> client(std::make_unique<Client>("localhost:1234"));
client->set_read_timeout(std::chrono::minutes(10));
std::atomic<bool> stop{false};
std::thread t([&] {
client->Get("/event1", [&](const char *data, size_t data_length) -> bool {
std::cout << std::string(data, data_length) << "\n";
return !stop;
});
});
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "stop\n";
stop = true;
client->stop();
std::cout << "stop done\n";
std::cout << "destroy\n";
client.reset();
std::cout << "destroy done\n";
t.join();
}
server.cpp
#include "httplib.h"
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>
using namespace httplib;
using namespace std;
class EventDispatcher {
public:
EventDispatcher() {}
void wait_event(DataSink *sink) {
unique_lock<mutex> lk(m_);
int id = id_;
cv_.wait(lk, [&] { return cid_ == id; });
sink->write(message_.data(), message_.size());
}
void send_event(const string &message) {
lock_guard<mutex> lk(m_);
cid_ = id_++;
message_ = message;
cv_.notify_all();
}
private:
mutex m_;
condition_variable cv_;
atomic_int id_{0};
atomic_int cid_{-1};
string message_;
};
int main(void) {
EventDispatcher ed;
Server svr;
svr.Get("/event1", [&](const Request & /*req*/, Response &res) {
cout << "connected to event1..." << endl;
res.set_chunked_content_provider("text/event-stream",
[&](size_t /*offset*/, DataSink &sink) {
ed.wait_event(&sink);
return true;
});
});
thread t([&] {
int id = 0;
while (true) {
this_thread::sleep_for(chrono::seconds(1));
// cout << "send event: " << id << std::endl;
std::stringstream ss;
ss << "data: " << id << "\n\n";
ed.send_event(ss.str());
id++;
}
});
svr.listen("localhost", 1234);
}
Question:
Is this the correct way to stop and destroy the client gracefully? Any suggestions or workarounds would be greatly appreciated.
Metadata
Metadata
Assignees
Labels
No labels