3

我正在使用 gRPC 进行 C++ 应用程序(gRPC 服务器)和 Java 应用程序(gRPC 客户端)之间的进程间通信。一切都在一台机器上运行。我想为客户端提供关闭服务器的可能性。我的想法是在 proto 中将 RPC 函数添加到服务中,这样就可以了。

C++ 实现将是:

class Service : public grpcGeneratedService
{
public:
......
private:  
    grpc::Server* m_pServer;
};
grpc::Status Service::ShutDown(grpc::ServerContext* pContext, const ShutDownRequest* pRequest, ShutDownResponse* pResponse)
{
    if (m_pServer)
        m_pServer->Shutdown();
    return grpc::Status(grpc::StatusCode::OK, "");
}

但是,在处理完所有 RPC 调用之前,ShutDown 会阻塞,这意味着死锁。有什么优雅的方式来实现它吗?

4

2 回答 2

12

我使用的 std::promise 方法与您的方法几乎一模一样。

// Somewhere in the global scope :/
std::promise<void> exit_requested;

// My method looks nearly identical to yours 
Status CoreServiceImpl::shutdown(ServerContext *context, const SystemRequest *request, Empty*)
{
  LOG(INFO) << context->peer() << " - Shutdown request acknowledged.";
  exit_requested.set_value();
  return Status::OK;
}

为了完成这项工作,我调用server->Wait()了第二个线程并等待未来exit_requested阻止关闭调用的承诺:

auto serveFn = [&]() {
  server->Wait();
};

std::thread serving_thread(serveFn);

auto f = exit_requested.get_future();
f.wait();
server->Shutdown();
serving_thread.join();

一旦我有了这个,我也能够通过信号处理程序支持干净关闭:

auto handler = [](int s) {
  exit_requested.set_value();
};
std::signal(SIGINT, handler);
std::signal(SIGTERM, handler);
std::signal(SIGQUIT, handler);

到目前为止,我对这种方法感到满意,它使我保持在 gRPC 和标准 c++ 库的范围内。而不是使用一些全局范围的承诺(我必须在我的服务实现源中将其声明为外部),我可能应该考虑一些更优雅的东西。

这里需要注意的一点是,多次设置 Promise 的值会引发异常。如果您以某种方式同时发送关闭消息,则可能会发生这种情况pkill -2 my_awesome_service。当我的持久层出现死锁阻止关闭完成时,我实际上遇到了这个问题,当我尝试再次发送 SIGINT 时,服务反而中止了!对于我的需要,这仍然是一个可以接受的解决方案,但我很想听听可以解决或解决这个小问题的替代方案。

于 2016-03-23T15:34:32.093 回答
0

您可以从 ShutDown() 处理程序创建一个 std::function 并在单独的线程(或线程池)中运行该函数。这将允许将 RPC 的处理与关闭逻辑的执行分离并消除死锁。

于 2015-11-04T04:43:35.367 回答