这个问题涉及
etcd
具体的问题,但我认为这个问题与
gRPC
一般来说。
我在努力创造
etcd公司
Watch
对于一些键,由于文档很少,我看了一下诺基亚
implementation
很容易使代码适应我的需要,我想出了第一个版本,它工作得很好,创建了
WatchCreateRequest
,并在密钥更新时启动回调到现在为止,一直都还不错。然后我试着加了不止一把钥匙看。惨败!
ClientAsyncReaderWriter
在这种情况下无法读/写。现在来回答这个问题。
如果我班上有下列成员
Watch::Stub watchStub;
CompletionQueue completionQueue;
ClientContext context;
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
WatchResponse reply;
我想支持多个
Watches
加上我的类,我想我必须持有几个变量每手表,而不是作为类成员。
首先,我想,
WatchResponse reply
应该是每个
手表
是的。我不太确定
stream
,我应该每人拿一个吗
手表
? 我几乎可以肯定
context
可以重复使用
手表
100%确定
stub
和
completionQueue
可重复使用
手表
是的。
所以问题是我的猜测正确吗?什么是线程安全?没有找到任何文档描述从多线程使用哪些对象是安全的,以及我必须在何处同步访问。
任何文档链接(
not this one
)将不胜感激!
在将成员拆分为单个成员之前测试代码
监视
财产
(我知道,没有正常关机)
using namespace grpc;
class Watcher
{
public:
using Callback = std::function<void(const std::string&, const std::string&)>;
Watcher(std::shared_ptr<Channel> channel) : watchStub(channel)
{
stream = watchStub.AsyncWatch(&context, &completionQueue, (void*) "create");
eventPoller = std::thread([this]() { WaitForEvent(); });
}
void AddWatch(const std::string& key, Callback callback)
{
AddWatch(key, callback, false);
}
void AddWatches(const std::string& key, Callback callback)
{
AddWatch(key, callback, true);
}
private:
void AddWatch(const std::string& key, Callback callback, bool isRecursive)
{
auto insertionResult = callbacks.emplace(key, callback);
if (!insertionResult.second) {
throw std::runtime_error("Event handle already exist.");
}
WatchRequest watch_req;
WatchCreateRequest watch_create_req;
watch_create_req.set_key(key);
if (isRecursive) {
watch_create_req.set_range_end(key + "\xFF");
}
watch_req.mutable_create_request()->CopyFrom(watch_create_req);
stream->Write(watch_req, (void*) insertionResult.first->first.c_str());
stream->Read(&reply, (void*) insertionResult.first->first.c_str());
}
void WaitForEvent()
{
void* got_tag;
bool ok = false;
while (completionQueue.Next(&got_tag, &ok)) {
if (ok == false) {
break;
}
if (got_tag == (void*) "writes done") {
// Signal shutdown
}
else if (got_tag == (void*) "create") {
}
else if (got_tag == (void*) "write") {
}
else {
auto tag = std::string(reinterpret_cast<char*>(got_tag));
auto findIt = callbacks.find(tag);
if (findIt == callbacks.end()) {
throw std::runtime_error("Key \"" + tag + "\"not found");
}
if (reply.events_size()) {
ParseResponse(findIt->second);
}
stream->Read(&reply, got_tag);
}
}
}
void ParseResponse(Callback& callback)
{
for (int i = 0; i < reply.events_size(); ++i) {
auto event = reply.events(i);
auto key = event.kv().key();
callback(event.kv().key(), event.kv().value());
}
}
Watch::Stub watchStub;
CompletionQueue completionQueue;
ClientContext context;
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
WatchResponse reply;
std::unordered_map<std::string, Callback> callbacks;
std::thread eventPoller;
};