C ++ 11: std :: thread внутри класса, выполняющего функцию-член с инициализацией потока в конструкторе - PullRequest
14 голосов
/ 11 мая 2011

Я пытаюсь использовать std :: thread из C ++ 11. Я нигде не мог найти, возможно ли иметь std :: thread внутри класса, выполняющего один из его функций-членов. Рассмотрим пример ниже ... В моей попытке (ниже), функция запускается ().

Я компилирую с gcc-4.4 с флагом -std = c ++ 0x.

#ifndef RUNNABLE_H
#define RUNNABLE_H

#include <thread>

class Runnable
{
    public:
        Runnable() : m_stop(false) {m_thread = std::thread(Runnable::run,this); }
        virtual ~Runnable() { stop(); }
        void stop() { m_stop = false; m_thread.join(); }
    protected:
        virtual void run() = 0;
        bool m_stop;
    private:
        std::thread m_thread;
};


class myThread : public Runnable{
protected:
    void run() { while(!m_stop){ /* do something... */ }; }
};

#endif // RUNNABLE_H

Я получаю эту ошибку и другие: (та же ошибка с и без $ this)

Runnable.h|9|error: no matching function for call to ‘std::thread::thread(<unresolved overloaded function type>, Runnable* const)’|

При передаче указателя.

* * 1010

Ответы [ 2 ]

16 голосов
/ 11 мая 2011

Вот код, который нужно обдумать:

#ifndef RUNNABLE_H
#define RUNNABLE_H

#include <atomic>
#include <thread>

class Runnable
{
public:
    Runnable() : m_stop(), m_thread() { }
    virtual ~Runnable() { try { stop(); } catch(...) { /*??*/ } }

    Runnable(Runnable const&) = delete;
    Runnable& operator =(Runnable const&) = delete;

    void stop() { m_stop = true; m_thread.join(); }
    void start() { m_thread = std::thread(&Runnable::run, this); }

protected:
    virtual void run() = 0;
    std::atomic<bool> m_stop;

private:
    std::thread m_thread;
};


class myThread : public Runnable
{
protected:
    void run() { while (!m_stop) { /* do something... */ }; }
};

#endif // RUNNABLE_H

Некоторые примечания:

  • Объявление m_stop простым bool, каким вы были, ужасно недостаточно;читать о барьерах памяти
  • std::thread::join может выдать, поэтому вызов его без деструктора try..catch является безрассудным
  • std::thread и std::atomic<> не копируются, поэтому Runnable должен быть помечен как таковой, если только для того, чтобы избежать предупреждений C4512 с помощью VC ++
15 голосов
/ 11 мая 2011

Это неправильный подход.

Проблема в том, что, пока объект находится в стадии разработки, его тип все еще не является самым производным типом, а типом выполняемого конструктора. Это означает, что при запуске потока объект все еще является Runnable, и вызов run() может быть отправлен на Runnable::run(), который является чисто виртуальным, и это, в свою очередь, приведет к неопределенному поведению.

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

...