【发布时间】:2016-04-16 08:13:00
【问题描述】:
我想通过包装 C++11 中的 std::thread 类来使用我自己的 Thread 实现,这样我就可以处理我想要的异常。
这是我的包装类:
#include <Types.hpp>
#include <thread>
#include <exception>
#include <functional>
class Thread
{
private:
std::exception_ptr exceptionPtr;
std::thread thread;
public:
using Id = std::thread::id;
using NativeHandleType = std::thread::native_handle_type;
Thread() noexcept = default;
Thread(Thread &&t) noexcept :
exceptionPtr(std::move(t.exceptionPtr)),
thread(std::move(t.thread))
{
}
Thread &operator =(Thread &&t) noexcept
{
exceptionPtr = std::move(t.exceptionPtr);
thread = std::move(t.thread);
return *this;
}
template<typename Callable, typename... Args>
Thread(Callable &&f, Args &&... args) :
exceptionPtr(nullptr),
thread([&](Callable &&f, Args &&... args)
{
try
{
std::once_flag flag;
std::call_once(flag, f, args...);
}
catch (...)
{
exceptionPtr = std::current_exception();
}
}, f, args...)
{
if (exceptionPtr != nullptr)
{
std::rethrow_exception(exceptionPtr);
}
}
bool joinable() const noexcept
{
return thread.joinable();
}
void join()
{
thread.join();
}
void detach()
{
thread.detach();
}
Id getId() const noexcept
{
return thread.get_id();
}
NativeHandleType nativeHandle()
{
return thread.native_handle();
}
static uint32_t hardwareConcurrency() noexcept
{
return std::thread::hardware_concurrency();
}
static void wait(Time t)
{
std::this_thread::sleep_for(t);
}
};
如果没有参数,效果很好:
Thread([&]() { /* do something */ }).detach();
...但是如果我尝试传递可变参数:
Thread(&GUI::refreshTask, this, refreshDelay).detach();
...编译时出现错误:
buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional: 在 'struct std::_Bind_simple)(std::chrono::duration > ); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI::)(std::chrono::duration >), CRH:: GUI,std::chrono::duration >)>': buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/thread:137:47: 来自 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = CRH::Thread::Thread(Callable&&, Args&& ...) [with Callable = void (CRH::GUI::)(std::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1; _Args = {void (CRH::GUI::&)(std::chrono::duration >), CRH::GUI const&, std::chrono::duration >&}]' /home/cyril/Documents/crh-2016/src/robot2/../core/Thread.hpp:72:30: 'CRH::Thread::Thread(Callable&&, Args&& ...) [with Callable =无效 (CRH::GUI::)(std::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]' src/core/GUI.cpp:90:57:从这里需要 buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional:1697:61: 错误:'class std::result_of)(std ::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI::)(std::chrono::duration >), CRH:: GUI,std::chrono::duration >)>' typedef typename result_of<_callable>::type result_type; ^ buildroot-2014.02/output/host/usr/i586-buildroot-linux-uclibc/include/c++/4.8.2/functional:1727:9: 错误:'class std::result_of)(std ::chrono::duration >); Args = {CRH::GUI const, std::chrono::duration >&}]::__lambda1(void (CRH::GUI::)(std::chrono::duration >), CRH:: GUI,std::chrono::duration >)>' _M_invoke(_Index_tuple<_indices...>)
可能会更清楚一点……但对 GCC 来说要求太高了。
知道如何解决这个问题吗?
解决方案
#include <Types.hpp>
#include <thread>
#include <exception>
#include <functional>
class Thread
{
private:
std::exception_ptr exceptionPtr;
std::thread thread;
public:
using Id = std::thread::id;
using NativeHandleType = std::thread::native_handle_type;
Thread() noexcept = default;
Thread(Thread &&t) noexcept :
exceptionPtr(std::move(t.exceptionPtr)),
thread(std::move(t.thread))
{
}
Thread &operator =(Thread &&t) noexcept
{
exceptionPtr = std::move(t.exceptionPtr);
thread = std::move(t.thread);
return *this;
}
template<typename Callable, typename... Args>
Thread(Callable &&f, Args &&... args) :
exceptionPtr(nullptr),
thread([&](typename std::decay<Callable>::type &&f, typename std::decay<Args>::type &&... args)
{
try
{
std::bind(f, args...)();
}
catch (...)
{
exceptionPtr = std::current_exception();
}
}, std::forward<Callable>(f), std::forward<Args>(args)...)
{
}
bool joinable() const noexcept
{
return thread.joinable();
}
void join()
{
thread.join();
if (exceptionPtr != nullptr)
{
std::rethrow_exception(exceptionPtr);
}
}
void detach()
{
thread.detach();
}
Id getId() const noexcept
{
return thread.get_id();
}
NativeHandleType nativeHandle()
{
return thread.native_handle();
}
static uint32_t hardwareConcurrency() noexcept
{
return std::thread::hardware_concurrency();
}
static void wait(Time t)
{
std::this_thread::sleep_for(t);
}
};
【问题讨论】:
-
将
thread([&](Callable &&f, Args &&... args)替换为thread([&](typename std::decay<Callable>::type&& f, typename std::decay<Args>::type&&... args)是否有效? -
以下划线后跟大写字母或包含两个连续下划线 (
__THREAD_HPP) 的名称保留给实现。不要使用它们。 -
Complete rules @PeteBecker 指出的。
-
它使用 std::decay 编译谢谢。在测试时,我发现一些可能非常正常的事情:std::call_once 仅在第一次传递参数的情况下调用 Callable 对象并忽略 orhers :S 我从来没有遇到过定义问题。
-
你的大部分错误信息都被破坏了。
标签: c++ multithreading c++11 templates stdthread