I am trying to implement a ThreadPool,but the clang compiler is giving me an error, which I do not know how to fix. My ThreadPool consists of 1 thread for planning and adding tasks to the queue (Scheduler), 1 thread for taking the tasks out of the queue and assigning separate threads to them(Executor), and child threads for each task. The problem arises in the Executor section:
struct Executor {
std::shared_ptr<SharedData> data_ptr_;
// constructor
explicit Executor (std::shared_ptr<SharedData>& data_ptr):
data_ptr_ (data_ptr)
{}
// methods
void execute () {
while (true) {
auto cur_task = data_ptr_ -> queue_.Take();
if (cur_task == std::nullopt) break;
std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)};
// ...
}
// join child threads here
}
void executeChild (Task task) {
// ...
task();
// ...
}
};
The compiler does not like this line:
std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)};
The error message that it produces is incomprehensible to me :(
In template: attempt to use a deleted function error occurred here in instantiation of function template specialization 'std::__thread_execute<std::unique_ptr<std::__thread_struct>, void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detail::proper... in instantiation of function template specialization 'std::__thread_proxy<std::tuple<std::unique_ptr<std::__thread_struct>, void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detai... in instantiation of function template specialization 'std::thread::thread<void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detail::property<true, false, void ()>>), tp::Executor ... '~__nat' has been explicitly marked deleted here
Are there any errors in my code? What is the compiler saying?
CodePudding user response:
The issue that cur_task
is a std::optional<Task>
and you pass this std::optional<Task>
directly to executeChild()
. But executeChild()
expects not a std::optional<Task>
but a Task
. Since you check if the optional is nullopt
before creating the thread, you probably want to use
std::thread child_thread {&Executor::executeChild, this, std::move(*cur_task)};
The *
in front of cur_task
is operator*
, which assumes that the optional contains a value and returns a reference to the contained value (if it doesn't, you have undefined behavior). Note there is also std::optional::value()
which throws if the optional is empty.
Reproducible example: The following code was adapted from your code, and shows the '~__nat' has been explicitly marked deleted here
error with clang 14 and libc (example on godbolt)
#include <memory>
#include <thread>
#include <optional>
struct Task{
void operator()(){}
};
struct SharedData{
std::optional<Task> Take() { return {}; }
};
struct Executor {
std::shared_ptr<SharedData> data_ptr_;
// constructor
explicit Executor (std::shared_ptr<SharedData>& data_ptr):
data_ptr_ (data_ptr)
{}
// methods
void execute () {
while (true) {
auto cur_task = data_ptr_ -> Take();
if (cur_task == std::nullopt) break;
// Mistake in the following line: Need to use *cur_task
std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)};
// ...
}
// join child threads here
}
void executeChild (Task task) {
// ...
task();
// ...
}
};
Error:
In file included from <source>:2:
/opt/compiler-explorer/clang-14.0.0/bin/../include/c /v1/thread:282:5: error: attempt to use a deleted function
_VSTD::__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
^
/opt/compiler-explorer/clang-14.0.0/bin/../include/c /v1/__config:826:15: note: expanded from macro '_VSTD'
#define _VSTD std
^
/opt/compiler-explorer/clang-14.0.0/bin/../include/c /v1/thread:293:12: note: in instantiation of function template specialization 'std::__thread_execute<std::unique_ptr<std::__thread_struct>, void (Executor::*)(Task), Executor *, std::optional<Task>, 2UL, 3UL>' requested here
_VSTD::__thread_execute(*__p.get(), _Index());
^
/opt/compiler-explorer/clang-14.0.0/bin/../include/c /v1/thread:309:54: note: in instantiation of function template specialization 'std::__thread_proxy<std::tuple<std::unique_ptr<std::__thread_struct>, void (Executor::*)(Task), Executor *, std::optional<Task>>>' requested here
int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
^
<source>:26:21: note: in instantiation of function template specialization 'std::thread::thread<void (Executor::*)(Task), Executor *, std::optional<Task>, void>' requested here
std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)};
^
/opt/compiler-explorer/clang-14.0.0/bin/../include/c /v1/type_traits:1885:5: note: '~__nat' has been explicitly marked deleted here
~__nat() = delete;
^
1 error generated.
Compiler returned: 1
So clang with libc does not really provide a helpful error message, but neither does clang with stdlibc nor gcc nor MSVC.