std :: thread: как объявить поток в теле класса как обычный член? - PullRequest
2 голосов
/ 13 февраля 2012

Я хочу иметь поток для каждого экземпляра объекта Page. Одновременно может выполняться только один из них (просто проверяет, является ли указатель на текущий запущенный поток присоединяемым или нет ..)

class Page : public std::vector<Step>
{
    // ....
    void play();
    void start(); // check if no other thread is running. if there is a running thread, return. else join starter
    std::thread starter; // std::thread running this->play()
    static std::thread* current; // pointer to current running thread
    // ...
};

Я хочу иметь возможность запускать starter потоков Page объектов. например, вот так:

Page x , y , z;
// do some stuff for initialize pages..
x.start();
// do some other work
y.start(); // if x is finished, start y otherwise do nothing
// do some other lengthy work
z.start(); // if x and y are not running, start z

Мне не удается объявить started членом Page. Я обнаружил, что это из-за того факта, что std::thread s может быть инициализирован только во время объявления. (или что-то подобное, потому что невозможно скопировать поток)

void x()
{
}
//...
std::thread t(x);          // this is ok
std::thread r;             // this is wrong, but I need this !
r = std::thread(this->y);  // no hope
r = std::thread(y);        // this is wrong too

Ответы [ 2 ]

3 голосов
/ 13 февраля 2012

Вы можете инициализировать поток для запуска функции, используя список инициализатора члена. Например, рассмотрим этот конструктор для Page:

class Page {
public:
    Page(); // For example

private:
    std::thread toRun;
};

Page::Page() : toRun(/* function to run */) {
    /* ... */
}

Обратите внимание, как мы используем список инициализации внутри конструктора Page для инициализации toRun функции, которую следует запустить. Таким образом, toRun инициализируется так, как если бы вы объявили его как локальную переменную

std::string toRun(/* function to run */);

Тем не менее, есть две основные проблемы, которые, я думаю, вы должны решить в своем коде. Во-первых, вы должны не наследовать от std::vector или любого из стандартных классов коллекций. Эти классы не имеют своих деструкторов, помеченных virtual, что означает, что вы можете легко вызвать неопределенное поведение, если попытаетесь трактовать свой Page как std::vector. Вместо этого рассмотрите возможность заставить Page держать std::vector как прямой подобъект. Кроме того, вы не должны выставлять std::thread члена класса. Члены данных должны, как правило, быть private, чтобы увеличить инкапсуляцию, упростить изменение класса в будущем и не дать людям нарушать все инварианты вашего класса.

Надеюсь, это поможет!

2 голосов
/ 14 февраля 2012

Никогда не наследуйте публично от контейнера std, если код не предназначен для выброса кода. Честно говоря, это ужасно, как часто выбрасываемый код становится рабочим кодом, когда наступает время пуша.

Я понимаю, что вы не хотите воспроизводить весь интерфейс std::vector. Это утомительное письмо, боль в поддержке и, честно говоря, может создавать ошибки.

Попробуйте вместо этого

class Page: private std::vector
{
public:
  using std::vector::push_back;
  using std::vector::size;
  // ...
};

Игнорирование проблемы std::vector, это должно работать для параллельной части проблемы.

class Page
{
  ~Page( void )
  {
    m_thread.join();
  }

  void start( void );

private:

  // note this is private, it must be to maintain the s_running invariant
  void play( void )
  {
    assert( s_current == this );

    // Only one Page at a time will execute this code.

    std::lock_guard<std::mutex> _{ s_mutex };
    s_running = nullptr;
  }

  std::thread m_thread;

  static Page* s_running;
  static std::mutex s_mutex;
};

Page* Page::s_running = nullptr;
std::mutex Page::s_mutex;
std::condition Page::s_condition;

void Page::start( void )
{
  std::lock_guard<std::mutex> _{ s_mutex };

  if( s_running == nullptr )
  {
    s_running = this;
    m_thread = std::thread{ [this](){ this->play(); } };
  }
}

Это решение может иметь проблемы с порядком инициализации, если экземпляр Page был создан до main()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...