Pass parameters to std::thread wrapper
In the error message, you can see the difference void (*)()
vs void (&)()
. That's because std::thread's constructor parameters are std::decay
ed.
Add also std::ref
to f
:
template< class Function, class... Args>
ManagedThread::ManagedThread( Function&& f, Args&&... args):
mActive( false),
mThread( threadFunction< Function, Args...>, std::ref(mActive), std::ref(f), std::forward<Args>(args)...)
{
}
The answer by @O'Neil is correct, but I would like to offer a simple lambda approach, since you've tagged this as C++14
.
template<class Function, class... Args>
ManagedThread::ManagedThread(Function&& f, Args&&... args):
mActive(false),
mThread([&] /*()*/ { // uncomment if C++11 compatibility needed
mActive = true;
std::forward<Function>(f)(std::forward<Args>(args)...);
mActive = false;
})
{}
This would eliminate the need for an external function all together.
O'Neil and DeiDei got here first, and they're correct as far as I can tell. However, I'm still posting my solution to your problem.
Here's something that would work better:
#include <atomic>
#include <thread>
#include <utility>
class ManagedThread {
public: /* Methods: */
template <class F, class ... Args>
explicit ManagedThread(F && f, Args && ... args)
: m_thread(
[func=std::forward<F>(f), flag=&m_active](Args && ... args)
noexcept(noexcept(f(std::forward<Args>(args)...)))
{
func(std::forward<Args>(args)...);
flag->store(false, std::memory_order_release);
},
std::forward<Args>(args)...)
{}
bool isActive() const noexcept
{ return m_active.load(std::memory_order_acquire); }
private: /* Fields: */
std::atomic<bool> m_active{true};
std::thread m_thread;
};
It makes use of lambdas instead, and correctly uses std::atomic<bool>
instead of volatile
to synchronize the state, and also includes the appropriate noexcept()
specifiers.
Also note, that the underlying std::thread
is not joined or detached properly before destruction, hence leading to std::terminate()
being called.
I rewrote the test code as well:
#include <chrono>
#include <iostream>
int main() {
ManagedThread mt1(
[]() noexcept
{ std::this_thread::sleep_for(std::chrono::milliseconds(500)); });
std::cout << "thread 1 active = " << std::boolalpha << mt1.isActive()
<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "thread 1 active = " << std::boolalpha << mt1.isActive()
<< std::endl;
}