drogon icon indicating copy to clipboard operation
drogon copied to clipboard

同样的程序运行于多核机器和单核机器,一个正常一个崩溃?

Open bethebest0622 opened this issue 1 year ago • 3 comments

请看如下代码

#include <drogon/drogon.h>

auto cclient_ = drogon::HttpClient::newHttpClient("https://fapi.binance.com");

int main() {
  std::thread t([] () {
    drogon::app().disableSigtermHandling();
    drogon::app().run();
  }); 
  t.detach();

  while (true) {
    auto req = drogon::HttpRequest::newHttpRequest();
    req->setMethod(drogon::HttpMethod::Get);
    req->setContentTypeString("application/json");
    const auto & [req_result, reponse_ptr] = cclient_->sendRequest(req);
    sleep(20);
  }
}

这段代码多核机器正常,单核机器报错:

a.out: /usr/local/include/drogon/HttpClient.h:132: std::pair<drogon::ReqResult, std::shared_ptr<drogon::HttpResponse> > drogon::HttpClient::sendRequest(const drogon::HttpRequestPtr&, double): Assertion `!getLoop()->isInLoopThread() && "Deadlock detected! Calling a sync API from the same loop as " "the HTTP client processes on will deadlock the event loop"' failed.
[1]    1506059 abort      ./a.out

为啥单核会遇到死锁呢?按我的理解这段代码只有一个线程

bethebest0622 avatar Jun 19 '24 07:06 bethebest0622

不要定义成全局 cclient_

#include <drogon/drogon.h>

int main() {
	std::thread t([]() {
		drogon::app().disableSigtermHandling();
		drogon::app().run();
	});
	t.detach();
	sleep(1);
	auto cclient_ = drogon::HttpClient::newHttpClient("https://fapi.binance.com");
	while (true) {
		auto req = drogon::HttpRequest::newHttpRequest();
		req->setMethod(drogon::HttpMethod::Get);
		req->setContentTypeString("application/json");
		const auto& [req_result, reponse_ptr] = cclient_->sendRequest(req);
		sleep(20);
	}
}

nqf avatar Jun 19 '24 08:06 nqf

不要定义成全局 cclient_

#include <drogon/drogon.h>

int main() {
	std::thread t([]() {
		drogon::app().disableSigtermHandling();
		drogon::app().run();
	});
	t.detach();
	sleep(1);
	auto cclient_ = drogon::HttpClient::newHttpClient("https://fapi.binance.com");
	while (true) {
		auto req = drogon::HttpRequest::newHttpRequest();
		req->setMethod(drogon::HttpMethod::Get);
		req->setContentTypeString("application/json");
		const auto& [req_result, reponse_ptr] = cclient_->sendRequest(req);
		sleep(20);
	}
}

这个原理可以简单讲讲吗

bethebest0622 avatar Jun 19 '24 08:06 bethebest0622

the HTTP client processes on will deadlock the event loop

你可以定义成全局, 但是你要保证 drogon::app().run(); 那个线程先被执行, 至于原理你看看 run 那个函数, 创建 drogon::HttpClient::newHttpClient对象时候, 如果你不传递Loop, 它就会用这个 Loop 单例 , 这个 loop 单例 默认 main 函数线程中的, 因此 你发送时候 触发断言 失败了, 但是 如果run 线程 先被执行以后, 他就被moveToCurrentThread, 所以就可以工作了

void HttpAppFrameworkImpl::run()
{
    if (!getLoop()->isInLoopThread())
    {
        getLoop()->moveToCurrentThread();
    }

/// Make sure that the main event loop is initialized in the main thread.
drogon::InitBeforeMainFunction drogon::HttpAppFrameworkImpl::initFirst_([]() {
    HttpAppFrameworkImpl::instance().getLoop()->runInLoop(f);
});

nqf avatar Jun 19 '24 08:06 nqf