In my program I have a Master class (grpc async client) which distributes work to all the Workers (grpc async servers), and it does this via a class called WorkerClient which handles all communication overhead.
My Master class tries to setup a (detached) background thread to wait for the response from the server, and this is where my difficulty arises.
One strategy I've tried was to make my "AsyncComplete" function part of the WorkerClient class (identical to an approach for a recent program involving async client-server grpc based on the Async-Greeter tutorial on grpc.io), the class details for this approach are below.
class WorkerClient {
public:
WorkerClient(std::shared_ptr<grpc::Channel> channel);
void MapReduceWork(masterworker::WorkReq);
void AsyncComplete(void *, void *, int);
struct AsyncClientCall {
masterworker::WorkReply reply;
grpc::ClientContext context;
grpc::Status status;
std::unique_ptr<grpc::ClientAsyncResponseReader<masterworker::WorkReply>> rsp_reader;
};
std::mutex mtx;
std::unique_ptr<masterworker::MasterWorker::Stub> stub;
grpc::CompletionQueue cq;
masterworker::WorkReq work_req;
ClientState state;
};
class Master {
public:
Master(const MapReduceSpec&, const std::vector<FileShard>&);
......
private:
std::mutex mtx;
std::vector<FileShard> map_tasks;
std::vector<ReduceTask *> reduce_tasks;
std::vector<WorkerClient *> clients;
std::vector<std::string> m_interm_files;
std::vector<FileShard> shards;
MapReduceSpec mr_config;
};
Here are the relevant function details
void WorkerClient::AsyncComplete(void *c, void *m, int client_num)
{
void *got_tag = NULL;
bool ok = false;
Master *mast = static_cast<Master*>(m);
WorkerClient *client = static_cast<WorkerClient*>(c);
cq.Next(&got_tag, &ok);
if (ok == false) {
fprintf(stderr, "cq->Next false!\n");
return;
}
......
}
The call to create the thread
void Master::RunMapJob()
{
// clients[] is of type WorkerClient
ptr = new std::thread(&WorkerClient::AsyncComplete,
static_cast<void*>(clients[i]), static_cast<void*>(this), i);
ptr->detach();
......
}
And finally, the problem itself
g++ -c master.cc -I../external/include -std=c++11 -g
In file included from /usr/include/c++/4.8/mutex:42:0,
from master.h:3,
from master.cc:2:
/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’:
/usr/include/c++/4.8/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (WorkerClient::*)(void*, void*, int); _Args = {void*, void*, int&}]’
master.cc:223:65: required from here
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (WorkerClient::*)(void*, void*, int)>(void*, void*, int)>’
_M_invoke(_Index_tuple<_Indices...>)
^
make: *** [master.o] Error 1
So far, I have ruled out the obvious things, like not using std::ref to pass variable references to the thread function, and just in general not passing the correct thread function arguments. I have also tried to make AsyncComplete a static stand-alone function, and that didn't work either because the call to cq.Next (changed to WorkerClient->cq.Next()) was throwing a std::bad_alloc exception (not able to figure that one out either as the CompletionQueue code is behind the scenes).
If it helps, I was able to find the /usr/include/c++/4.8/functional line that seems to be choking during compile (below)
typedef typename result_of<_Callable(_Args...)>::type result_type;
Can anyone help me explain both why this is failing to compile, and what a proper fix might look like? I'm new to posting questions on here so feedback is welcome, and I know this is long, but I wanted to make sure I had all the information.
Thanks in advance.
[System details: ubuntu 14.04, protobufs 3.0, grpc built from source for protobufs 3.0]
This line is the problem:
ptr = new std::thread(&WorkerClient::AsyncComplete, static_cast<void*>(clients[i]), static_cast<void*>(this), i)
The constructor of std::thread
takes a functor and arguments to it. You are supplying &WorkerClient::AsyncComplete
without giving an instance of WorkerClient
to it. I guess that a client is actually contained in clients[i]
. If you try
ptr = new std::thread(std::bind(&WorkerClient::AsyncComplete, clients[i], static_cast<void*>(clients[i]), static_cast<void*>(this), i))
it should compile.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.