[RESOLVED] packaged task error - with thread & future
Hi
I'm following this youtube video while learning about packaged tasks and futures.
The code presented about two thirds of the way into the video, is as follows:
Code:
#include <future>
#include <iostream>
#include <deque>
int factorial(int N) {
int res = 1;
for (int i=N; i>1; i--) {
res *= i;
}
return res;
}
std::deque<std::packaged_task<int()> > task_q;
void thread_1() {
std::packaged_task<int()> t;
t = std::move(task_q.front());
t();
}
int main() {
std::thread t1(thread_1);
std::packaged_task<int()> t(std::bind(factorial, 6)); // "int" removed
std::future<int> fu = t.get_future();
task_q.push_back(t);
std::cout << fu.get() << std::endl;
t1.join();
return 0;
}
The idea behind the code is to take a packaged task and push into onto a queue, a running thread then pops the task and and executes the function object represented by the task.
A get() is then performed on the future (fu), associated with the packaged task (task_q), to obtain the result of the factorial.
But I get the following compile error:
Code:
g++ -Wall -o "thread18_example" "thread18_example.cpp" -L /usr/lib/x86_64-linux-gnu -lpthread -lboost_system (in directory: /home/C++/learn2_c++)
In file included from /usr/include/x86_64-linux-gnu/c++/6/bits/c++allocator.h:33:0,
from /usr/include/c++/6/bits/allocator.h:46,
from /usr/include/c++/6/string:41,
from /usr/include/c++/6/stdexcept:39,
from /usr/include/c++/6/array:39,
from /usr/include/c++/6/tuple:39,
from /usr/include/c++/6/functional:55,
from /usr/include/c++/6/future:38,
from thread18_example.cpp:1:
/usr/include/c++/6/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::packaged_task<int()>; _Args = {const std::packaged_task<int()>&}; _Tp = std::packaged_task<int()>]’:
/usr/include/c++/6/bits/alloc_traits.h:475:4: required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::packaged_task<int()>; _Args = {const std::packaged_task<int()>&}; _Tp = std::packaged_task<int()>; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::packaged_task<int()> >]’
/usr/include/c++/6/bits/stl_deque.h:1522:30: required from ‘void std::deque<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::packaged_task<int()>; _Alloc = std::allocator<std::packaged_task<int()> >; std::deque<_Tp, _Alloc>::value_type = std::packaged_task<int()>]’
thread18_example.cpp:27:21: required from here
/usr/include/c++/6/ext/new_allocator.h:120:4: error: use of deleted function ‘std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = int; _ArgTypes = {}]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from thread18_example.cpp:1:0:
/usr/include/c++/6/future:1513:7: note: declared here
packaged_task(const packaged_task&) = delete;
^~~~~~~~~~~~~
Compilation failed.
Can anybody suggest why the error and a remedy?
Thanks
Re: packaged task error - with thread & future
From the error messages,
Code:
packaged_task(const packaged_task&) = delete;
The problem is as above. The copy constructor for class packaged_task has been deleted so instances of class packaged_task can't be copied - they can only be moved.
Re: packaged task error - with thread & future
Thanks,
I've modified the code, to what is shown a bit later in the same video, to the following:
Code:
#include <future>
#include <iostream>
#include <deque>
int factorial(int N) {
int res = 1;
for (int i=N; i>1; i--) {
res *= i;
}
return res;
}
std::deque<std::packaged_task<int()> > task_q;
std::mutex mu;
std::condition_variable cond;
void thread_1() {
std::packaged_task<int()> t;
{
std::unique_lock<std::mutex> locker(mu); // use unique_lock, instead of lock_guard, because of condition_variable that blocks & unblocks
cond.wait(locker, []() { return !task_q.empty();}); // wait for task package to be available on queue
t = std::move(task_q.front()); // the move occurs, since t is not referenced in the main thread
task_q.pop_front();
}
t();
}
int main() {
std::thread t1(thread_1);
std::packaged_task<int()> t(std::bind(factorial, 5)); // "int" removed
std::future<int> fu = t.get_future();
{ // since queue is shared, use lock_guard
std::lock_guard<std::mutex> locker(mu);
task_q.push_back(std::move(t)); // perform move when placing onto queue
}
cond.notify_one();
std::cout << fu.get() << std::endl;
t1.join();
return 0;
}
The code works now, and moves the task, as you suggested. In addition, since the queue is shared, a lock_guard and unique_lock is introduced to protect the pushing & popping.