在 C++ 线程中使用类成员
Posted
技术标签:
【中文标题】在 C++ 线程中使用类成员【英文标题】:Using class members in C++ thread 【发布时间】:2020-04-04 00:19:03 【问题描述】:有没有办法使用 C++11 线程生成一个可以以某种方式访问类成员的线程?
假设我像这样实例化一个对象,
FITS_file <float> fits_file;
类在头文件中定义为:
template <class T>
class FITS_file
private:
std::mutex fits_mutex; //!< used to block writing_file semaphore in multiple threads
bool writing_file; //!< semaphore indicates file is being written
std::unique_ptr<CCfits::FITS> pFits; //!< pointer to FITS data container
public:
FITS_file()
this->writing_file = false;
;
long write_image(T* data, Archon::Information& info)
std::thread(write_image_thread, array, info).detach(); // spawn thread here
return 0;
static void write_image_thread(std::valarray<T> &data, Archon::Information &info)
// lock mutex, set writing_file=true, does the work, set writing_file=false
// must be static (?) for C++ threads
// but can't access this->fits_mutex and friends because it's static
工作线程 (write_image_thread) 必须是静态的,但如果它是静态的,则我无法访问线程内的 this->
成员。
我尝试像这样生成线程:
std::thread([&]()this->write_image_thread(array, info);).detach();
但是 (a) 我不知道这是否正确(即使它可以编译); (b) 我似乎在传递给线程的内容方面受到限制; (c) 我仍然无法访问this->
成员。
我知道如果我使用 Boost 线程,我可以做我想做的事,也许我只需要这样做,但我想知道是否有办法从这里直接使用 C++11。
【问题讨论】:
您是否尝试过让write_image_thread
成为常规类方法,而不是静态线程函数,并且它们只是调用std::thread(&FITS_file<T>, this);
,而write_image_thread
像任何其他类方法一样正常访问其成员?请注意,您有责任(以某种方式)确保对象在线程终止之前一直存在。
添加到 Sam:确保(以某种方式)对象在线程终止之前一直存在为此,我将删除 detach()
并制作 @ 987654330@班级成员。然后析构函数可以检查线程是否有joinable()
和join()
线程以防万一。
@SamVarshavchik 我认为这就是答案...查看我提出的完整答案。
【参考方案1】:
根据 cmets,我想我已经找到了答案。我使用了@Sam Varshavchik 的建议,并将线程函数定义为:
void write_image_thread(std::valarray<T> &data, Archon::Information &info, FITS_file<T> *obj)
const std::lock_guard<std::mutex> lock(obj->fits_mutex); // access private members!
obj->writing_file = true; // access private members!
try
obj->pFits->pHDU().addKey("EXPOSURE", fpixel,"Total Exposure Time");
// and more stuff...
catch (CCfits::FitsError& error)
// handle faults
// all done
obj->writing_file = false;
然后调用它:
std::thread([&]()this->write_image_thread(std::ref(array), std::ref(info), this);).detach();
这似乎有效!所以我认为这就是答案(为了安全起见,我将在将其标记为已回答之前尝试更多地练习它)。
不确定提出附加问题是否是一种好习惯,但它们是相关的......
1) std::ref() 函数真的有必要吗?我将它们添加为明确的,但没有它们似乎也可以工作。
2) 我不得不承认我并不真正理解我正在使用的 lambda 表达式;我在另一个 Stack Overflow 问题上发现了这一点(C++ 11 Thread initialization with member functions compiling error——在对原始问题的评论中)。我尝试了各种方法让它在没有 lambda 的情况下工作,但不能让它编译。
换句话说,这个:
std::thread(&FITS_file<T>::write_image_thread, std::ref(array), std::ref(info), this).detach();
不起作用;它给出了以下错误:
In file included from /usr/include/c++/4.8.2/mutex:42:0,
from /home/user/archon-interface/include/common.h:13,
from /home/user/archon-interface/src/archon.cpp:9:
/usr/include/c++/4.8.2/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (FITS_file<float>::*)(std::valarray<float>&, Archon::Information&, FITS_file<float>*)>(std::reference_wrapper<std::valarray<float> >, std::reference_wrapper<Archon::Information>, FITS_file<float>*)>’:
/usr/include/c++/4.8.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (FITS_file<float>::*)(std::valarray<float>&, Archon::Information&, FITS_file<float>*); _Args = std::reference_wrapper<std::valarray<float> >, std::reference_wrapper<Archon::Information>, FITS_file<float>* const]’
/home/user/archon-interface/include/fits.h:137:94: required from ‘long int FITS_file<T>::write_image(T*, Archon::Information&) [with T = float]’
/home/user/archon-interface/src/archon.cpp:1697:52: required from here
/usr/include/c++/4.8.2/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (FITS_file<float>::*)(std::valarray<float>&, Archon::Information&, FITS_file<float>*)>(std::reference_wrapper<std::valarray<float> >, std::reference_wrapper<Archon::Information>, FITS_file<float>*)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.8.2/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (FITS_file<float>::*)(std::valarray<float>&, Archon::Information&, FITS_file<float>*)>(std::reference_wrapper<std::valarray<float> >, std::reference_wrapper<Archon::Information>, FITS_file<float>*)>’
_M_invoke(_Index_tuple<_Indices...>)
^
make[2]: *** [CMakeFiles/archonserver.dir/src/archon.cpp.o] Error 1
make[1]: *** [CMakeFiles/archonserver.dir/all] Error 2
make: *** [all] Error 2
但正如我所说,如果我使用 lambda,那么它就可以工作!所以也许我应该对此感到高兴。
【讨论】:
以上是关于在 C++ 线程中使用类成员的主要内容,如果未能解决你的问题,请参考以下文章
如何在一个类中执行 C++ 多线程(将线程引用保持为成员 var)
C++:使用 pthread_create 创建新线程,以运行类成员函数