如何异步正确使用grpc(ClientAsyncReaderWriter)

时间:2017-10-16 09:46:52

标签: c++ grpc refcounting

我找不到一个grpc示例,说明如何使用ClientAsyncReaderWriter (有一个吗?)。我自己尝试了一些东西,但是参考计数有问题。我的问题来自对代码的追踪。

struct grpc_call的成员类型gpr_refcount名为ext_ref。 ClientContext C ++对象包装grpc_call,并在成员grpc_call *call_;中保留它。只有当ext_ref为0时,才能删除此grpc_call指针。

当我与ClientReader同步使用grpc时:

  • 在其实现中,它使用CreateCall()和PerformOps()添加到ext_ref(ext_ref == 2)。
  • 然后我使用从ext_ref中减去的Pluck(),以便(ext_ref == 1)。
  • 最后一次使用~ClientContext()从ext_ref中减去,以便ext_ref == 0删除调用

但当我与ClientAsyncReaderWriter异步使用grpc时:

  • 首先使用asyncXXX(),此API使用CreateCall()并注册Write()(ext_ref == 2)。
  • 然后它使用AsyncNext()获取标记...必须使用写或读操作符。
  • 永远ext_ref > 1,除非你没有处理got_event。

我这样称呼它:

struct Notice
{
    std::unique_ptr<
        grpc::ClientAsyncReaderWriter<ObserveNoticRequest, EventNotice>
    >                          _rw;
    ClientContext              _context;
    EventNotice                _rsp;
}

注册线程

CompletionQueue *cq = new CompletionQueue;
Notice *notice = new Notice;
notice->rw = stub->AsyncobserverNotice(&context, cq, notice); 

// here context.call_.ext_ref is 2

获取CompletionQueue事件线程

void *tag = NULL;
bool ok = false;
CompletionQueue::NextStatus got = CompletionQueue::NextStatus::TIMEOUT;
gpr_timespec deadline;
deadline.clock_type = GPR_TIMESPAN;
deadline.tv_sec = 0;
deadline.tv_nsec = 10000000;

got = cq->AsyncNext<gpr_timespec>(&tag, &ok, deadline);

if (GOT_EVENT == got) {
    if (tag != NULL) {
        Notice *notice = (Notice *)tag;
        notice->_rw->Read(&_rsp, notice);

        // here context.call_.ext_ref is 2.
        // now I want to stop this CompletionQueue. 

        delete notice;

        // use ~ClientContext(), ext_ref change to 1
        // but only ext_ref == 0, call_ be deleted
    }
}

1 个答案:

答案 0 :(得分:2)

请查看此文件client_async.cc,以便充分利用ClientAsyncReaderWriter。如果您仍然感到困惑,请创建一个非常干净的问题再现,我们将进一步研究。