Art*_*zuk 6 c++ multithreading c++11
我们先来看看具体的功能:
void boo1 () { std::cout << "boo1\n"; }
void boo2 (std::string) { std::cout << "boo2\n"; }
struct X {
void boo3 () { std::cout << "boo3\n"; }
void boo4 (std::string) { std::cout << "boo4\n"; }
};
Run Code Online (Sandbox Code Playgroud)
我希望这些函数可以通过一些"保护"功能来执行,它可以进行异常保护(下面的说明).所以,我写了两个函数,一个用于自由函数,另一个用于成员函数:
template <typename C, typename... Args>
typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, Args&&... args) {
std::cout << "not memfun\n";
c (std::forward<Args> (args)...);
}
template <typename C, typename T, typename... Args>
typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, T* o, Args&&... args) {
std::cout << "memfun\n";
(o->*c) (std::forward<Args> (args)...);
}
Run Code Online (Sandbox Code Playgroud)
现在我想执行boo1(),boo2(),X::boo3()并X::boo4()在新的线程,但与使用"保护" foo()功能.所以,没有任何问题,我可以这样做:
X x;
std::thread th1 {&foo<void (*) ()>, &boo1};
std::thread th2 {&foo<void (*) (std::string), std::string>, &boo2, "Hello"};
std::thread th3 {&foo<void (X::*) (), X>, &X::boo3, &x};
std::thread th4 {&foo<void (X::*) (std::string), X, std::string>, &X::boo4, &x, "Hello"};
Run Code Online (Sandbox Code Playgroud)
所以,更进一步,我已经编写了线程包装类来停止使用显式std::join()或std::detach().当析构函数处于运行状态时,会调用其中一个.为了简化这个例子,我只使用了其中一个.所以,代码看起来像这样:
class Th {
public:
template <typename C,
typename = typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type,
typename... Args>
Th (C&& c, Args... args) // (X)
: t {foo<C, Args...>, std::forward<C> (c), std::forward<Args> (args)...} {}
template <typename C,
typename = typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type,
typename T,
typename... Args>
Th (C&& c, T* o, Args... args) // (Y)
: t { foo<C, T, Args...>, std::forward<C> (c), o, std::forward<Args> (args)...} {}
~Th () { t.join (); }
private:
std::thread t;
};
Run Code Online (Sandbox Code Playgroud)
并且通过这种实现没有问题,以下用例:
X x;
Th h1 {&boo1};
Th h2 {&boo2, "Hello"};
Th h3 {&X::boo3, &x};
Th h4 {&X::boo4, &x, "Hello"};
Run Code Online (Sandbox Code Playgroud)
工作除外.然而,这里有一个缺陷 - 没有完美的转发.如果我更改了(X),并(Y) Args...给Args&&...它需要的话,代码不能与某些错误的编译,其中之一是:
error: no type named ‘type’ in ‘class std::result_of<void (*(void (*)(std::basic_string<char>), const char*))(void (*&&)(std::basic_string<char>), const char (&)[6])>’
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,std::bind()在std::thread构造函数中不能做它的工作,或者如果我错了就纠正我.
我的问题是:在这种情况下,我该怎么做才能利用完美转发?
用于编译的编译器是GCC 4.8.1.
有希望的解释:我希望foo()函数围绕调用c()with try并catch确保捕获异常,在某种日志记录机制中处理此信息,并在需要时重新抛出异常,并为Th类的用户提供透明性.
将左值引用传递给 时std::thread,需要将它们包装在 中std::reference_wrapper。例如,您可以通过以下方式进行操作:
namespace detail
{
template<typename T>
std::reference_wrapper<T> forward_to_thread(T& t, std::true_type) {
return std::ref(t);
}
template<typename T>
T&& forward_to_thread(T&& t, std::false_type) {
return std::move(t);
}
}
template<typename T>
auto forward_to_thread(T&& t)
-> decltype(detail::forward_to_thread(std::forward<T>(t), std::is_lvalue_reference<T>{}))
{
return detail::forward_to_thread(std::forward<T>(t), std::is_lvalue_reference<T>{});
}
Run Code Online (Sandbox Code Playgroud)
然后你只需替换初始化中的std::forward调用:forward_to_threadthread
class Th {
public:
template <typename C,
typename = typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type,
typename... Args>
Th (C&& c, Args&&... args) // (X)
: t {foo<C, Args...>, std::forward<C> (c), forward_to_thread<Args> (std::forward<Args>(args))...} {}
template <typename C,
typename = typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type,
typename T,
typename... Args>
Th (C&& c, T* o, Args&&... args) // (Y)
: t { foo<C, T, Args...>, std::forward<C> (c), o, forward_to_thread<Args> (std::forward<Args>(args))...} {}
~Th () { t.join (); }
private:
std::thread t;
};
Run Code Online (Sandbox Code Playgroud)
这确实适用于 gcc 4.8.2 [链接]
如果您可以使用更新的编译器,请考虑使用std::invoke(C++17) 以获得更简洁和可读的代码(即this)。