grpc c ++ события асинхронного завершения очереди - PullRequest
6 голосов
/ 22 октября 2019

Я пытаюсь понять поток асинхронной модели grpc c ++. Эта статья ( ссылка ) уже объясняет многие мои сомнения. Вот код для grpc_asycn_server . Чтобы понять, когда CompletionQueue получает запросы, я добавил несколько операторов print следующим образом:

Сначала внутри функции HandleRpcs ().

void HandleRpcs() {
    // Spawn a new CallData instance to serve new clients.
    new CallData(&service_, cq_.get());
    void* tag;  // uniquely identifies a request.
    bool ok;
    int i = 0;
    while (true) {
      std::cout << i << std::endl; ///////////////////////////////
      // Block waiting to read the next event from the completion queue. The
      // event is uniquely identified by its tag, which in this case is the
      // memory address of a CallData instance.
      // The return value of Next should always be checked. This return value
      // tells us whether there is any kind of event or cq_ is shutting down.
      GPR_ASSERT(cq_->Next(&tag, &ok));
      GPR_ASSERT(ok);
      static_cast<CallData*>(tag)->Proceed();
      i++;
    }
  }

и внутри функции continue ():

void Proceed() {
  if (status_ == CREATE) {
    // Make this instance progress to the PROCESS state.
    status_ = PROCESS;

    // As part of the initial CREATE state, we *request* that the system
    // start processing SayHello requests. In this request, "this" acts are
    // the tag uniquely identifying the request (so that different CallData
    // instances can serve different requests concurrently), in this case
    // the memory address of this CallData instance.
    std::cout<<"RequestSayHello called"<<std::endl; ////////////////////////////
    service_->RequestSayHello(&ctx_, &request_, &responder_, cq_, cq_,
                              this);
  } else if (status_ == PROCESS) {
    // Spawn a new CallData instance to serve new clients while we process
    // the one for this CallData. The instance will deallocate itself as
    // part of its FINISH state.
    new CallData(service_, cq_);

    // The actual processing.
    std::string prefix("Hello ");
    reply_.set_message(prefix + request_.name());

    // And we are done! Let the gRPC runtime know we've finished, using the
    // memory address of this instance as the uniquely identifying tag for
    // the event.
    status_ = FINISH;
    responder_.Finish(reply_, Status::OK, this);
  } else {
    std::cout<<"deallocated"<<std::endl; ////////////////////////////
    GPR_ASSERT(status_ == FINISH);
    // Once in the FINISH state, deallocate ourselves (CallData).
    delete this;
  }
}

После запуска сервера и одного клиента ( client ) сервер выводит следующее:

RequestSayHello called
i = 0
RequestSayHello called
i = 1
deallocated
i = 2

Второй RequestSayHello called имеет смысл из-засоздание нового CallData экземпляра. Мой вопрос Почему функция proceed() выполняется во второй раз, а deallocated печатается?

1 Ответ

5 голосов
/ 27 октября 2019

Структура очереди завершения (cq_) обрабатывает несколько типов событий, включая события ответа и . Первый вызов proceed() входит в стадию PROCESS конечного автомата для объекта CallData.

На этом этапе:
1. Создается новый объект CallData;это вставляет событие запроса в cq_, как вы упомянули
2. responder_ вызывается с объектом ответа;это вставляет событие ответа в cq_

При получении события ответа от cq_, proceed() вызывается снова для первого CallData объекта, который сейчас находится в состоянии FINISH, поэтомувыполняется очистка и печатается deallocated.

...