Использование членов класса в потоке C ++ - PullRequest
0 голосов
/ 04 апреля 2020

Есть ли способ, используя потоки 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) должен быть stati c, но если это stati c, тогда я не могу получить доступ к this-> членам внутри потока.

Я пытался порождать поток так:

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

, но (а) я не знаю, правильно ли это (даже если он компилируется); и (б) я, кажется, ограничен в том, что я могу передать нити; и (c) я все еще не могу получить доступ к this-> членам.

Я понимаю, что могу делать то, что хочу, если использую потоки Boost, и, возможно, мне просто нужно это сделать, но мне было интересно если бы был путь отсюда, используя прямой C ++ 11.

1 Ответ

0 голосов
/ 06 апреля 2020

Основываясь на комментариях, я думаю, что нашел ответ. Я использовал предложение @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) Я должен признать, что ДЕЙСТВИТЕЛЬНО не понимаю лямбда-выражение, которое я использую; Я обнаружил это в другом вопросе переполнения стека ( C ++ 11 Инициализация потока с ошибкой компиляции функций-членов - в комментарии к исходному вопросу). Я пробовал разные способы заставить его работать без лямбды, но не могу заставить его скомпилироваться иначе.

Другими словами, это:

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

Но, как я уже сказал, если я использую лямбду, то это работает! Так что, может быть, я должен быть счастлив этим.

...