【问题标题】:grpc & protobuf -- error: no type named 'type' in std::result_of<>grpc & protobuf -- 错误:在 std::result_of<> 中没有名为 'type' 的类型
【发布时间】:2017-12-05 23:54:22
【问题描述】:

在我的程序中,我有一个 Master 类(grpc 异步客户端),它将工作分配给所有 Worker(grpc 异步服务器),它通过一个名为 WorkerClient 的类来处理所有通信开销。

我的 Master 类尝试设置一个(分离的)后台线程来等待来自服务器的响应,这就是我遇到困难的地方。

我尝试过的一个策略是让我的“AsyncComplete”函数成为 WorkerClient 类的一部分(与最近基于 grpc.io 上的 Async-Greeter 教程的涉及异步客户端-服务器 grpc 的程序的方法相同),此方法的类详细信息如下。

    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;
        };

以下是相关功能详情

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;
    }
    ......
}

创建线程的调用

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();
    ......
}

最后,问题本身

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

到目前为止,我已经排除了一些明显的事情,比如不使用 std::ref 将变量引用传递给线程函数,并且通常不传递正确的线程函数参数。我还尝试使 AsyncComplete 成为一个静态独立函数,但这也不起作用,因为对 cq.Next 的调用(更改为 WorkerClient->cq.Next())抛出了 std::bad_alloc 异常(不是能够弄清楚这一点,因为 CompletionQueue 代码在幕后)。

如果有帮助,我可以找到 /usr/include/c++/4.8/functional 在编译期间似乎卡住的行(如下)

typedef typename result_of<_Callable(_Args...)>::type result_type;

谁能帮我解释一下为什么编译失败,以及正确的修复方法是什么样的?我是新来在这里发布问题的,所以欢迎提供反馈,我知道这很长,但我想确保我掌握了所有信息。

提前致谢。

[系统详细信息:ubuntu 14.04、protobufs 3.0、grpc 从 protobufs 3.0 的源代码构建]

【问题讨论】:

    标签: c++ multithreading c++11 protocol-buffers grpc


    【解决方案1】:

    这行是问题所在:

    ptr = new std::thread(&WorkerClient::AsyncComplete, static_cast<void*>(clients[i]), static_cast<void*>(this), i)

    std::thread 的构造函数接受一个函子和参数。您正在提供 &amp;WorkerClient::AsyncComplete 而不给它一个 WorkerClient 的实例。我猜想一个客户端实际上包含在clients[i] 中。如果你尝试

    ptr = new std::thread(std::bind(&WorkerClient::AsyncComplete, clients[i], static_cast<void*>(clients[i]), static_cast<void*>(this), i))
    

    它应该可以编译。

    【讨论】:

    • 天哪,你是救生员...谢谢!在我之前的程序中,我有一个类似的线程创建调用,但它实际上并没有任何绑定调用,但仍然传递了参数。知道为什么线程 ctor 有时需要绑定,而其他时候不需要绑定吗? ----- 例如 --------- threads.push_back(new std::thread(&Vclient::AsyncComplete, vendor[i], static_cast(this))); ------------ 这里的“线程”是 std::thread 指针的向量,包含该代码的程序可以正常编译和运行。
    • 如果您查看en.cppreference.com/w/cpp/thread/thread 上的std::thread 文档示例,它会告诉您第一个参数必须是函子:Function&amp;&amp; f, Args&amp;&amp;... args。当你想为一个方法创建一个仿函数时,你必须将该方法绑定到该类的一个实例。如果是独立函数或静态类方法,则不必绑定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2021-04-21
    • 2014-12-21
    相关资源
    最近更新 更多