【发布时间】:2016-06-25 00:35:50
【问题描述】:
在我的代码中,我希望所有线程都从一个类型继承,而该类型又从 std::thread 继承。原因很常见,我敢肯定:
- 来自线程外部的停止请求和来自线程内部的继续检查,无论它是哪种类型的线程,都以相同的方式完成。换句话说,每种类型的线程都没有自己的停止/检查逻辑。
- 在线程中运行的代码不必关心它是否真的在线程中运行,除了调用
thread::shouldBeRunning(),如果不在线程中,它总是返回true。
但是,(我认为)我如何将模板参数/值从std::thread 的子类传递给包装函数存在问题,在下面的代码中是static void run(thread * This, Function&& Func, Args&&... a)
#include <thread>
#include <atomic>
#include <iostream>
class thread
{
friend int main(int, char **);
private:
std::atomic<bool> m_ShouldBeRunning;
std::atomic<bool> m_Running;
int m_Error;
std::thread m_Thread;
#ifdef WIN32
__declspec(thread) static thread * m_Local;
#else
__thread static thread * m_Local;
#endif
template <typename Function, typename... Args>
static void run(thread * This, Function&& Func, Args&&... a)
{
thread::m_Local = This;
try
{
std::bind(std::forward<Function>(Func), std::forward<Args>(a)...)();
}
catch (int Error)
{
This->m_Error = Error;
}
This->m_Running.store(false, std::memory_order_release);
}
public:
template <typename Function, typename... Args>
thread(Function&& Func, Args&&... a)
: m_ShouldBeRunning(true)
, m_Running(true)
, m_Error(0)
, m_Thread(&thread::run<Function, Args...>,
this,
std::forward<Function>(Func),
std::forward<Args>(a)...)
{}
virtual ~thread()
{
try
{
stop();
m_Thread.join();
}
catch (...)
{
std::cerr << "caught exception in ~thread!";
}
}
bool isRunning() const { return m_Running.load(std::memory_order_acquire); }
static thread * get() { return thread::m_Local; }
static bool shouldBeRunning()
{
thread * Thread = thread::m_Local;
return (Thread)
? Thread->m_ShouldBeRunning.load(std::memory_order_acquire)
: true;
}
void stop() { m_ShouldBeRunning.store(false, std::memory_order_release); }
};
thread * thread::m_Local = NULL;
class doStuff
{
private:
int m_X;
float m_Y;
char m_Z;
public:
doStuff(int X, float Y, char Z)
: m_X(X), m_Y(Y), m_Z(Z) {}
void stuff(int X, float Y, char Z)
{
while (thread::shouldBeRunning())
{
std::cout << (X + m_X) << " " << (Y + m_Y) << " " << Z << m_Z << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
};
class threadDoStuff : public thread
{
public:
threadDoStuff(doStuff & Stuff, int X, float Y, char Z)
: thread(&doStuff::stuff,
&Stuff,
X,
Y,
Z)
{}
};
int main(int argc, char ** argv)
{
doStuff stuff(3, 2.0f, 'z');
threadDoStuff stuffThread(stuff, 5, 1.0f, 'a');
std::this_thread::sleep_for(std::chrono::seconds(30));
return 0;
}
MSVC 2013 吐出一条长长的错误链,最顶端是:
------ Build started: Project: test, Configuration: Debug Win32 ------
main.cpp
c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1149): error C2664: 'void (thread *,Function &&,doStuff *&&,int &,float &,char &)' : cannot convert argument 3 from 'doStuff *' to 'doStuff *&&'
with
[
Function=void (__thiscall doStuff::* )(int,float,char)
]
You cannot bind an lvalue to an rvalue reference
【问题讨论】:
-
使用
&thread::run<Function, Args...>,您不再使用转发引用并强制将左值/右值引用传递给它。 -
改用
m_Thread(&thread::run<std::decay_t<Function>, std::decay_t<Args>...>, -
好的,我知道这会导致函数的定义方式和调用方式之间存在差异,但这样做会导致
error C2664: 'void (thread *,Function &&,doStuff *&&,int &&,float &&,char &&)' : cannot convert argument 6 from 'char' to 'char &&'
标签: c++ templates subclass variadic stdthread