我正在尝试实现一个thread
类,因为我自己定义了C ++ 11标准,因为我发现这是一个使用可变参数模板和C ++语言的其他高级功能的好方法。
据我所知,在使用 pthreads 库时,在创建线程时,分配给它的函数必须具有以下签名:void* method(void* param)
。
pthread_create
的第四个参数只允许传递一个参数。
在Internet上搜索,传递多个参数的最常用方法是将它们打包在一个结构中,并将该结构上的指针作为参数传递。
因为C ++ thread
类允许函数具有我们想要的参数,所以我查看了LLVM实现(肯定接近其他实现)并看到它们使用了代理函数,这对我来说似乎是最好的方式。
因为我不想使用forward
或decay
(它为LLVM制作的方式),如果可能的话,使它与众不同,因为复制/粘贴不会让我学到任何东西,我虽然可以使用可变模板函数作为代理。
以下是我的想法:
/** THREAD CLASS **/
template <typename _ret_type, typename... _args_types>
void*
__thread_proxy(void* p)
{
_ret_type(*fn)(_args_types...) = reinterpret_cast<_ret_type(*)(_args_types...)>(p);
std::cout << "Thread " << pthread_self() << " speaking! :)" << std::endl;
fn(6, 'a');
return bk::null_pointer;
}
class thread
{
pthread_t _tid;
public:
thread() :
_tid(0)
{ }
template <typename ret_type, typename... args_types>
thread(ret_type(*fn)(args_types...), args_types... args)
{
pthread_create(&_tid, 0, __thread_proxy<ret_type, args_types...>, &fn);
}
}
/** USAGE **/
void
test(int i, char c)
{
std::cout << "test: ";
while (i > 0) {
std::cout << c;
i--;
}
std::cout << std::endl;
}
int main(const int argc, const char** argv)
{
thread t(test, 6, 'a');
}
正如您所看到的,我此时无法传递参数,这就是为什么在__thread_proxy
函数中,我直接使用参数调用fn。
我已经使用pthread_create
的第四个参数来传递线程的入口点。因为入口点返回类型和参数类型作为模板参数传递,我虽然可以对参数做同样的事情。
然后我将代理代码修改为:
template <typename _ret_type, typename... _args_types, _args_types... args_values>
void*
__thread_proxy(void* p)
{
_ret_type(*fn)(_args_types...) = reinterpret_cast<_ret_type(*)(_args_types...)>(p);
std::cout << "Thread " << pthread_self() << " speaking! :)" << std::endl;
fn(args_values...);
return bk::null_pointer;
}
这里的问题是,即使尝试像这样__thread_proxy<ret_type, args_types..., args...>(&fn)
(来自线程的第二个构造函数)调用代理,也会返回以下错误:
没有用于调用'__thread_proxy'的匹配函数
的显式指定参数无效
忽略候选模板:模板参数'_args_types'
我从未见过这种消息,但是尝试自己解决这个问题至少4个小时,我认为问题在于,当花费参数包时,模板参数为__thread_proxy<void, int, char, 6, 'a'>
。看到这一点,我想我可以说编译器无法知道_args_types
的结束位置和args_values
的开始位置。
我指望你的灯光。我不是模板的新手,但我不是很常见,所以你给我的每一个资源,欢迎给我的提示。
- 提前致谢