|
@@ -174,6 +174,7 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
|
|
|
for (int i = 0; i < num_async_threads_; i++) {
|
|
|
cli_cqs_.emplace_back(new CompletionQueue);
|
|
|
next_issuers_.emplace_back(NextIssuer(i));
|
|
|
+ shutdown_state_.emplace_back(new PerThreadShutdownState());
|
|
|
}
|
|
|
|
|
|
using namespace std::placeholders;
|
|
@@ -189,7 +190,21 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
|
|
|
}
|
|
|
}
|
|
|
virtual ~AsyncClient() {
|
|
|
- FinalShutdownCQs();
|
|
|
+ for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) {
|
|
|
+ std::lock_guard<std::mutex> lock((*ss)->mutex);
|
|
|
+ (*ss)->shutdown = true;
|
|
|
+ }
|
|
|
+ for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
|
|
|
+ (*cq)->Shutdown();
|
|
|
+ }
|
|
|
+ this->EndThreads(); // Need "this->" for resolution
|
|
|
+ for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
|
|
|
+ void* got_tag;
|
|
|
+ bool ok;
|
|
|
+ while ((*cq)->Next(&got_tag, &ok)) {
|
|
|
+ delete ClientRpcContext::detag(got_tag);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
bool ThreadFunc(HistogramEntry* entry,
|
|
@@ -200,7 +215,12 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
|
|
|
if (cli_cqs_[thread_idx]->Next(&got_tag, &ok)) {
|
|
|
// Got a regular event, so process it
|
|
|
ClientRpcContext* ctx = ClientRpcContext::detag(got_tag);
|
|
|
- if (!ctx->RunNextState(ok, entry)) {
|
|
|
+ // Proceed while holding a lock to make sure that
|
|
|
+ // this thread isn't supposed to shut down
|
|
|
+ std::lock_guard<std::mutex> l(shutdown_state_[thread_idx]->mutex);
|
|
|
+ if (shutdown_state_[thread_idx]->shutdown) {
|
|
|
+ return true;
|
|
|
+ } else if (!ctx->RunNextState(ok, entry)) {
|
|
|
// The RPC and callback are done, so clone the ctx
|
|
|
// and kickstart the new one
|
|
|
auto clone = ctx->StartNewClone();
|
|
@@ -217,22 +237,13 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
|
|
|
protected:
|
|
|
const int num_async_threads_;
|
|
|
|
|
|
- void ShutdownCQs() {
|
|
|
- for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
|
|
|
- (*cq)->Shutdown();
|
|
|
- }
|
|
|
- }
|
|
|
- void FinalShutdownCQs() {
|
|
|
- for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
|
|
|
- void* got_tag;
|
|
|
- bool ok;
|
|
|
- while ((*cq)->Next(&got_tag, &ok)) {
|
|
|
- delete ClientRpcContext::detag(got_tag);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
private:
|
|
|
+ struct PerThreadShutdownState {
|
|
|
+ mutable std::mutex mutex;
|
|
|
+ bool shutdown;
|
|
|
+ PerThreadShutdownState() : shutdown(false) {}
|
|
|
+ };
|
|
|
+
|
|
|
int NumThreads(const ClientConfig& config) {
|
|
|
int num_threads = config.async_client_threads();
|
|
|
if (num_threads <= 0) { // Use dynamic sizing
|
|
@@ -241,9 +252,9 @@ class AsyncClient : public ClientImpl<StubType, RequestType> {
|
|
|
}
|
|
|
return num_threads;
|
|
|
}
|
|
|
-
|
|
|
std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
|
|
|
std::vector<std::function<gpr_timespec()>> next_issuers_;
|
|
|
+ std::vector<std::unique_ptr<PerThreadShutdownState>> shutdown_state_;
|
|
|
};
|
|
|
|
|
|
static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator(
|
|
@@ -259,10 +270,7 @@ class AsyncUnaryClient GRPC_FINAL
|
|
|
config, SetupCtx, BenchmarkStubCreator) {
|
|
|
StartThreads(num_async_threads_);
|
|
|
}
|
|
|
- ~AsyncUnaryClient() GRPC_OVERRIDE {
|
|
|
- ShutdownCQs();
|
|
|
- EndThreads();
|
|
|
- }
|
|
|
+ ~AsyncUnaryClient() GRPC_OVERRIDE {}
|
|
|
|
|
|
private:
|
|
|
static void CheckDone(grpc::Status s, SimpleResponse* response) {}
|
|
@@ -391,10 +399,7 @@ class AsyncStreamingClient GRPC_FINAL
|
|
|
StartThreads(num_async_threads_);
|
|
|
}
|
|
|
|
|
|
- ~AsyncStreamingClient() GRPC_OVERRIDE {
|
|
|
- ShutdownCQs();
|
|
|
- EndThreads();
|
|
|
- }
|
|
|
+ ~AsyncStreamingClient() GRPC_OVERRIDE {}
|
|
|
|
|
|
private:
|
|
|
static void CheckDone(grpc::Status s, SimpleResponse* response) {}
|
|
@@ -530,10 +535,7 @@ class GenericAsyncStreamingClient GRPC_FINAL
|
|
|
StartThreads(num_async_threads_);
|
|
|
}
|
|
|
|
|
|
- ~GenericAsyncStreamingClient() GRPC_OVERRIDE {
|
|
|
- ShutdownCQs();
|
|
|
- EndThreads();
|
|
|
- }
|
|
|
+ ~GenericAsyncStreamingClient() GRPC_OVERRIDE {}
|
|
|
|
|
|
private:
|
|
|
static void CheckDone(grpc::Status s, ByteBuffer* response) {}
|