mardi 5 décembre 2017

grpc & protobuf -- error: no type named 'type' in std::result_of<>

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]

Aucun commentaire:

Enregistrer un commentaire