vendredi 2 janvier 2015

How do I forward a function and a parameter pack into a lambda, into the constructor of std::thread?

I'm looking to implement an "interruptible" thread in C++11 along the lines of this answer.


I've parameterized my interruptible class so that it can wrap any class of thread that has a similar constructor (intended for std::thread, but should also work for something like boost::thread (nevermind boost::thread already has this functionality)). That part shouldn't matter.


Despite the linked answer having a few issues I had to correct, it makes good sense to me, so I'd like to figure out where I'm going wrong.


I've included the relevant source and the results.


interruptible.hpp



#include <atomic>
#include <exception>
#include <thread>

class interrupted_exception : public virtual std::exception
{
public:
char const *what() const noexcept { return "interrupted"; }
};


template <typename T>
class interruptible
{
public:
template <typename F, typename... A>
interruptible(F&& Function, A&&... Arguments) :
Interrupted(false),
Thread(
[](std::atomic_bool *Interrupted, F&& Function, A&&... Arguments)
{
LocalInterrupted = Interrupted;
Function(std::forward<A>(Arguments)...);
},
&this->Interrupted,
std::forward<F>(Function),
std::forward<A>(Arguments)...
)
{ }

void interrupt() { this->Interrupted = true; }
bool interrupted() const { return this->Interrupted; }

T *operator->() { return &this->Thread; }

static inline void check() noexcept(false)
{
if (!interruptible::LocalInterrupted)
return;

if (!interruptible::LocalInterrupted->load())
return;

throw interrupted_exception();
}

private:
static thread_local std::atomic_bool *LocalInterrupted;

std::atomic_bool Interrupted;
T Thread;
};

template <typename T>
thread_local std::atomic_bool *interruptible<T>::LocalInterrupted = nullptr;


main.cpp



#include <iostream>
#include <unistd.h>
#include <thread>

#include "interruptible.hpp"

void DoStuff()
{
try
{
while (true)
{
std::cout << "Loop" << std::endl;

sleep(1);

interruptible<std::thread>::check();
}
}
catch (interrupted_exception const &e)
{
std::cout << "Interrupted!" << std::endl;
}
}


int main()
{
interruptible<std::thread> a(DoStuff);

sleep(2);

std::cout << "Interrupting..." << std::endl;
a.interrupt();

sleep(2);

a->join();

return 0;
}


When I compile this with g++ -std=c++11 main.cpp (gcc 4.9.2), I get:



/usr/include/c++/4.9.2/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<interruptible<T>::interruptible(F&&, A&& ...) [with F = void (&)(); A = {}; T = std::thread]::<lambda(std::atomic_bool*, void (&)())>(std::atomic_bool*, void (*)())>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.9.2/functional:1695:9: error: no type named ‘type’ in ‘class std::result_of<interruptible<T>::interruptible(F&&, A&& ...) [with F = void (&)(); A = {}; T = std::thread]::<lambda(std::atomic_bool*, void (&)())>(std::atomic_bool*, void (*)())>’
_M_invoke(_Index_tuple<_Indices...>)
^


Any light that anyone can shed on this problem would be very appreciated!


Aucun commentaire:

Enregistrer un commentaire