Запуск потока через конструктор в C ++ 11 - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь выполнить программу, в которой я создаю очередь packaged_task и пытаюсь выполнить packaged_tasks в отдельном потоке. Я получаю следующую ошибку

Ошибка C2664 'std :: function <_Ret (void)> :: function (std :: function <_Ret (void)> &&)': невозможно преобразовать аргумент 1 из 'std :: _ Binder 'to' 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 голосов
/ 16 ноября 2018

Вы связываете нестатическую функцию-член класса, поэтому вам нужно указать объект, для которого функция-член вызывается. this отсутствует во всех звонках bind:

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

сделать то же самое для theMul и theAdd.

Вторая проблема, packaged_task объект не может быть скопирован, если вы хотите передать этот объект в качестве параметра push_back Вы должны разыграть packaged_task объект Rvalue ссылка, тогда packaged_task будет перемещен в вектор.

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

Все вышеизложенное устраняет ошибки при компиляции.

1) Поскольку packaged_task перемещается в методе theDiv, Вы не можете вызывать членов для этого объекта после выполнения операции перемещения. После нажатия 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
}

Сделайте то же самое с методами theAdd и theMul.

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
    }
}
0 голосов
/ 16 ноября 2018

У вас есть две ошибки в вашем коде. Во-первых, вы используете ваши связыватели неправильно. При связывании функции-члена первый аргумент должен иметь указатель на класс, в вашем случае this. Вот один пример фиксированного кода:

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

Однако использование лямбда-выражений обычно гораздо более интуитивно понятно и синтаксически, чем связыватели. Вот та же самая идея, выраженная с помощью лямбды:

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

Возможны другие проблемы с этим кодом, я только исправил ошибки компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...