在C ++ 11中通过构造函数启动线程

时间:2018-11-16 15:34:16

标签: c++ multithreading api sockets c++11

我正在尝试执行创建packaged_task队列的程序,并尝试在单独的线程中执行packaged_tasks。我收到以下错误

错误C2664'std :: function <_Ret(void)> :: function(std :: function <_Ret(void)> &&)':无法将参数1从'std :: _ Binder转换'到'std :: nullptr_t'

我的代码如下所示。关于此错误发生原因,是否可以有任何指南?

/*
****************************************************************************************************
                                        The Header File
****************************************************************************************************
*/


class CommandChannel {
private:
    std::thread commChannelThread;
    std::mutex commChannelmu;
    std::condition_variable commChannelcv;


    struct taskRequest
    {};
    struct taskResponse
    {};

    /* Creates a queue of packaged tasks that accepts one iu */
    std::deque< std::packaged_task<int()>> comm_ch_task_queue;

    void threadHandler(void);

protected:
    int p_impl_theAdd(int a, int b);
    int p_impl_theMul(int a, int b);
    int p_impl_theDiv(int a, int b);
public:
    /*Constructor and the Destructor*/
    CommandChannel();
    ~CommandChannel();

    /*The public functions */
    int theAdd(int a, int b);
    int theMul(int a, int b);
    int theDiv(int a, int b);
};

    /*
    ****************************************************************************************************
                                            The Implementation File
    ****************************************************************************************************
    */

/* Implementation Functions */
int CommandChannel::p_impl_theAdd(int a, int b)
{
    return a+b;
}

int CommandChannel::p_impl_theMul(int a, int b)
{
    return a*b;
}

int CommandChannel::p_impl_theDiv(int a, int b)
{
    return a / b;
}


/* COnstructors and Destructors */
CommandChannel::CommandChannel()
{
    /*Creating a new thread that runs the threadHandler function*/
    commChannelThread = std::thread(&CommandChannel::threadHandler, this);
}
CommandChannel::~CommandChannel()
{
    if (commChannelThread.joinable()) {
        commChannelThread.join();
        std::cout << "Command Channel Thread Joined " << std::endl;
    }
    else
        std::cout << "Problem in joining the Command Channel Thread" << std ::endl;
}

/*  User Public Functions  */
int CommandChannel::theAdd(int a, int b)
{
    /* Creating the packaged task with the the implementation pointer */
    std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theAdd, a, b));

    /* Pushing the task in the queue */
    {
        std::lock_guard<std::mutex> locker(commChannelmu);
        comm_ch_task_queue.push_back(t);
        commChannelcv.notify_one();
    }

    /* creating the placeholder for the return value */
    std::future<int> fu = t.get_future();

    /* getting the value from the future */
    return fu.get();

}

int CommandChannel::theMul(int a, int b)
{
    /* Create the packaged task with the pimpl */
    std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theMul, a, b));

    /* Pushing the task in the queue */
    {
        std::lock_guard<std::mutex> locker(commChannelmu);
        comm_ch_task_queue.push_back(t);
        commChannelcv.notify_one();
    }

    /* Creating the placeholder for the return value */
    std::future<int> fu = t.get_future();

    /*getting the value from the future*/
    return fu.get();
}

int CommandChannel::theDiv(int a, int b)
{
    /* Create the packaged tasks with the pimpl */
    std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theDiv, a, b));

    /*Pushing the task in the queue thorigh the mutex locks*/
    {
        std::lock_guard<std::mutex> locker(commChannelmu);
        comm_ch_task_queue.push_back(t);
        commChannelcv.notify_one();
    }
    /* Creating the placeholder for the return value */
    std::future<int> fu = t.get_future();

    /*getting the value from the future*/
    return fu.get();
}


/* 
   Thread Handler

   Pops the elemetns from the queue and then executes them
   the value goes to the called function through future references
*/
void CommandChannel::threadHandler()
{
    std::packaged_task<int()> t;
    {
        std::unique_lock<std::mutex> locker(commChannelmu);
        commChannelcv.wait(locker);
        t = std::move(comm_ch_task_queue.front());
        comm_ch_task_queue.pop_front();
    }
    t();
}


    /*
    ****************************************************************************************************
                                            Main
    ****************************************************************************************************
    */

int main()
{
    CommandChannel api;

    api.theAdd(2, 4);
    api.theDiv(6, 3);
    api.theMul(5, 7);

    return 0;
}

2 个答案:

答案 0 :(得分:0)

您的代码中有两个错误。首先,您使用的活页夹不正确。在绑定成员函数时,第一个参数应具有指向类的指针,在您的情况下为this。这是固定代码的一个示例:

std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theDiv, this, a, b));

但是,使用lambdas通常比活页夹更加直观和语法友好。这是用lambda表达的相同想法:

std::packaged_task<int()> t([this, a, b]() {return p_impl_theDiv(a, b);});

此外,一旦固定所有位置,您将遇到另一个问题-您正在复制packaged_task对象,同时将它们推入队列。这些对象不可复制,您必须移动。同样,这是此修复程序的一个实例:

comm_ch_task_queue.push_back(std::move(t));

此代码可能还有其他问题,我只修复了编译错误。

答案 1 :(得分:0)

您正在绑定类的非静态成员函数, 所以您需要指定对象 成员函数被调用。 this丢失 在bind的所有调用中:

std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theDiv, this, a, b));

theMultheAdd做同样的事情。

第二个问题,packaged_task对象无法复制, 如果要将此对象作为参数传递 push_back,您必须投射packaged_task对象 到右值引用,则packaged_task将被移动 进入向量。

comm_ch_task_queue.push_back(std::move(t));

以上所有都是为了消除编译期间的错误。

1) 由于packaged_tasktheDiv方法移动, 在执行移动操作后,您无法调用该对象的任何成员。 按下packaged_task后,您应该退出theDiv函数。

void CommandChannel::theDiv(int a, int b)
{
    /* Create the packaged tasks with the pimpl */
    std::packaged_task<int()> t(std::bind(&CommandChannel::p_impl_theDiv, this, a, b));

    /*Pushing the task in the queue thorigh the mutex locks*/
    {
        std::lock_guard<std::mutex> locker(commChannelmu);
        comm_ch_task_queue.push_back(std::move(t));
        commChannelcv.notify_one();
    }

    // access to t is forbidden
}

使用theAddtheMul方法做同样的事情。

2)您的线程函数仅从队列执行一项任务。 我认为那里缺少一些循环。您要将所有传入任务执行到队列中(注释中的详细信息):

void CommandChannel::threadHandler()
{
    std::packaged_task<int()> t;
    while (true) // inifite loop to process incoming tasks
    {
        std::unique_lock<std::mutex> locker(commChannelmu);
        commChannelcv.wait(locker,[this](){ return comm_ch_task_queue.size();});
        // wait returns if there is some task to be performed

        t = std::move(comm_ch_task_queue.front());
        comm_ch_task_queue.pop_front();
        std::future<int> f = t.get_future();
        t(); // perform task
        std::cout << f.get() << std::endl; // print value
    }
}