std::thread 的作用域线程包装器
scoped thread wrapper for std::thread
我正在尝试创建一个作用域线程。
#include <iostream>
#include <thread>
class ScopedThread {
public:
template< class Function, class... Args>
explicit ScopedThread( int id, Function&& f, Args&&... args)
: m_thread( std::ref(f), std::forward<Args>(args)...)
, id(std::move(id)) {
}
int getId() const { return id; }
~ScopedThread() { m_thread.join(); }
private:
std::thread m_thread;
int id;
};
class Worker {
public:
Worker(int id): thd(id, &Worker::work, this) { }
void work() {
for( int i = 0; i < 10; i++)
std::cout << "I am working" << std::endl;
}
private:
ScopedThread thd;
};
int main() {
Worker(1);
Worker(2);
Worker(3);
Worker(4);
}
当我 运行 代码时,它会转储核心。
#0 0x00007ffcfbbc6380 in ?? ()
#1 0x00000000004026c9 in std::_Mem_fn<void (Worker::*)()>::operator()<, void>(Worker*) const (this=0x7f0b43551de0, __object=0x7ffcfbbc63c0)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:601
#2 0x00000000004025cd in std::__invoke<void (Worker::*)(), Worker*> (__f=@0x7ffcfbbc6360: (void (Worker::*)(Worker * const)) 0x7ffcfbbc6380, this adjustment 4198629,
__args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x2abf>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:247
#3 0x0000000000402532 in std::reference_wrapper<void (Worker::*)()>::operator()<Worker*>(Worker*&&) const (this=0x1b27048,
__args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x57fb>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:467
#4 0x00000000004024d2 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x1b27040)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#5 0x0000000000402485 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::operator()() (this=0x1b27040)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#6 0x0000000000402119 in std::thread::_Impl<std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)> >::_M_run() (this=0x1b27028)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#7 0x00007f0b44103a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8 0x00007f0b43920184 in start_thread (arg=0x7f0b43552700) at pthread_create.c:312
#9 0x00007f0b4364d37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
有人能告诉我如何将成员函数和参数转发到底层 std::thread class 吗?我观察到,分段错误仅出现在 clang++ 中,而不出现在 gcc 中。
我的 objective 是让包装器 class 完全可以用 std::thread class 替换。包装器 class 接受线程 ID 的新参数。
您对 ScopedThread
的实施存在几个问题。
不需要单独处理Function&& f
。只需将其作为 args...
包的一部分处理即可。
不需要移动id
。
template< class... Args>
explicit ScopedThread( int id, Args&&... args)
: m_thread( std::forward<Args>(args)...)
, id(id) {
}
在调用 .join()
.
之前,您应该确保您的线程是可连接的
~ScopedThread() { if(m_thread.joinable()) m_thread.join(); }
正在应用这些更改 prevents the segmentation fault on clang++。
罪魁祸首是 std::ref(f)
- 您正在创建一个临时 reference_wrapper
并将其传递给 std::thread
的构造函数,该构造函数使用 std::invoke
来调用它。
根据 g++
和 UndefinedBehaviorSanitizer:
/usr/local/gcc-head/include/c++/7.0.1/bits/invoke.h:73:46:
runtime error: member call on misaligned address 0x7fff939ec8d3 for
type 'struct Worker', which requires 8 byte alignment
问题是您正在使用 std::ref(f)
创建对临时 的 引用,其中临时是 &Worker::work
.
我的 5 美分给研究该主题的任何人。
我清理了代码并实现了删除的构造函数:
class ScopedThread{
public:
template<class ...Args>
explicit ScopedThread(Args &&...args) : thread_(std::forward<Args>(args)...){}
ScopedThread(ScopedThread &&other){
thread_ = std::move(other.thread_);
}
ScopedThread &operator=(ScopedThread &&other){
thread_ = std::move(other.thread_);
return *this;
}
std::thread &operator*(){
return thread_;
}
std::thread const &operator*() const{
return thread_;
}
std::thread *operator->(){
return & operator*();
}
std::thread const *operator->() const{
return & operator*();
}
auto get_id() const{
return thread_.get_id();
}
auto join(){
if (thread_.joinable())
thread_.join();
}
~ScopedThread(){
join();
}
private:
std::thread thread_;
};
我正在尝试创建一个作用域线程。
#include <iostream>
#include <thread>
class ScopedThread {
public:
template< class Function, class... Args>
explicit ScopedThread( int id, Function&& f, Args&&... args)
: m_thread( std::ref(f), std::forward<Args>(args)...)
, id(std::move(id)) {
}
int getId() const { return id; }
~ScopedThread() { m_thread.join(); }
private:
std::thread m_thread;
int id;
};
class Worker {
public:
Worker(int id): thd(id, &Worker::work, this) { }
void work() {
for( int i = 0; i < 10; i++)
std::cout << "I am working" << std::endl;
}
private:
ScopedThread thd;
};
int main() {
Worker(1);
Worker(2);
Worker(3);
Worker(4);
}
当我 运行 代码时,它会转储核心。
#0 0x00007ffcfbbc6380 in ?? ()
#1 0x00000000004026c9 in std::_Mem_fn<void (Worker::*)()>::operator()<, void>(Worker*) const (this=0x7f0b43551de0, __object=0x7ffcfbbc63c0)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:601
#2 0x00000000004025cd in std::__invoke<void (Worker::*)(), Worker*> (__f=@0x7ffcfbbc6360: (void (Worker::*)(Worker * const)) 0x7ffcfbbc6380, this adjustment 4198629,
__args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x2abf>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:247
#3 0x0000000000402532 in std::reference_wrapper<void (Worker::*)()>::operator()<Worker*>(Worker*&&) const (this=0x1b27048,
__args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x57fb>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:467
#4 0x00000000004024d2 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x1b27040)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#5 0x0000000000402485 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::operator()() (this=0x1b27040)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#6 0x0000000000402119 in std::thread::_Impl<std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)> >::_M_run() (this=0x1b27028)
at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#7 0x00007f0b44103a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8 0x00007f0b43920184 in start_thread (arg=0x7f0b43552700) at pthread_create.c:312
#9 0x00007f0b4364d37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
有人能告诉我如何将成员函数和参数转发到底层 std::thread class 吗?我观察到,分段错误仅出现在 clang++ 中,而不出现在 gcc 中。
我的 objective 是让包装器 class 完全可以用 std::thread class 替换。包装器 class 接受线程 ID 的新参数。
您对 ScopedThread
的实施存在几个问题。
不需要单独处理
Function&& f
。只需将其作为args...
包的一部分处理即可。不需要移动
id
。template< class... Args> explicit ScopedThread( int id, Args&&... args) : m_thread( std::forward<Args>(args)...) , id(id) { }
在调用
之前,您应该确保您的线程是可连接的.join()
.~ScopedThread() { if(m_thread.joinable()) m_thread.join(); }
正在应用这些更改 prevents the segmentation fault on clang++。
罪魁祸首是 std::ref(f)
- 您正在创建一个临时 reference_wrapper
并将其传递给 std::thread
的构造函数,该构造函数使用 std::invoke
来调用它。
根据 g++
和 UndefinedBehaviorSanitizer:
/usr/local/gcc-head/include/c++/7.0.1/bits/invoke.h:73:46:
runtime error: member call on misaligned address 0x7fff939ec8d3 for type 'struct Worker', which requires 8 byte alignment
问题是您正在使用 std::ref(f)
创建对临时 的 引用,其中临时是 &Worker::work
.
我的 5 美分给研究该主题的任何人。
我清理了代码并实现了删除的构造函数:
class ScopedThread{
public:
template<class ...Args>
explicit ScopedThread(Args &&...args) : thread_(std::forward<Args>(args)...){}
ScopedThread(ScopedThread &&other){
thread_ = std::move(other.thread_);
}
ScopedThread &operator=(ScopedThread &&other){
thread_ = std::move(other.thread_);
return *this;
}
std::thread &operator*(){
return thread_;
}
std::thread const &operator*() const{
return thread_;
}
std::thread *operator->(){
return & operator*();
}
std::thread const *operator->() const{
return & operator*();
}
auto get_id() const{
return thread_.get_id();
}
auto join(){
if (thread_.joinable())
thread_.join();
}
~ScopedThread(){
join();
}
private:
std::thread thread_;
};