在 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-&gt; 成员。

我尝试像这样生成线程:

std::thread([&]()this->write_image_thread(array, info);).detach();

但是 (a) 我不知道这是否正确(即使它可以编译); (b) 我似乎在传递给线程的内容方面受到限制; (c) 我仍然无法访问this-&gt; 成员。

我知道如果我使用 Boost 线程,我可以做我想做的事,也许我只需要这样做,但我想知道是否有办法从这里直接使用 C++11。

【问题讨论】:

您是否尝试过让write_image_thread 成为常​​规类方法,而不是静态线程函数,并且它们只是调用std::thread(&amp;FITS_file&lt;T&gt;, 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++ 中运行类成员函数的线程

C++:使用 pthread_create 创建新线程,以运行类成员函数

如何在 C++ 类中创建四个线程

linux 之 pthread_create 实现类的成员函数做参数

使用 COM 在 C++ 中实例化 C# 类成员