Можно ли реализовать опрос с QThread без его подкласса? - PullRequest
3 голосов
/ 16 июня 2011

У меня есть класс, который является абстракцией некоторого устройства.

class Device  
{  
public:  
  ...  
  void Start();  
  void Stop();  
  void MsgLoop();

signals:
  void sMsgArrived();
}  

Start () и Stop () вызываются из потока GUI.Start () начинает новый поток, который запускает MsgLoop ().Это выглядит так:

void MsgLoop()  
{
   forever {  
      if(SUCCESS == ReadMsg()) //synchronous, non-blocking
      {
        ProcessMsg(); //quite fast
        emit sMsgArrived(); //this signal is connected with a slot in GUI thread  
      }
   }
}

Когда вызывается Stop (), программа должна вернуться из MsgLoop () и остановить поток.Как я могу реализовать это с QThread, не разбивая его на подклассы?

Ответы [ 3 ]

5 голосов
/ 16 июня 2011

Как правило, вы должны решить, кто будет отвечать за управление потоком. Это устройство или главное окно? Или, возможно, какой-то диспетчер устройств. В вашем случае устройство, вероятно, должно управлять своим собственным потоком, поэтому, если вы не хотите создавать его подкласс, используйте композицию:

class Device : QObject
{
    Q_OBJECT
public:
    Device(QObject * parent = NULL);
    void Start();  
    void Stop();  

private slots:
    void MsgLoop();

signals:
    void sMsgArrived();

private:
    QThread thread;
    bool stopThread;
};


Device::Device(QObject * parent) : QObject(parent)
{
    moveToThread(&thread);
    connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}

void Device::Start()
{
    stopThread = false;
    thread.start();
}

void Device::Stop()
{
    stopThread = true;
    thread.wait();      // if you want synchronous stop
}

void Device::MsgLoop()
{
  // your loop
  while(!stopThread)
    if(SUCCESS == ReadMsg())
    {
      ProcessMsg();
      emit sMsgArrived();
    }
  QThread::currentThread->quit();
}

ПРИМЕЧАНИЕ: остановка потока будет работать, только если ReadMsg действительно не является блокирующим. Если позже вы решите переключиться на блокировку чтения (и это, вероятно, подойдет для большинства случаев), вам придется найти другой способ остановить поток.

2 голосов
/ 16 июня 2011

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

Однако вы просите запустить цикл обработки сообщений forever .

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

class Device : public QObject
{
Q_OBJECT

public:
Device(QObject* parent = 0);
~Device();

public Q_SLOTS:
  void MsgLoop();

};

QThread* thread = new QThread;
Device* device = new Device;

void Widget::onBtnStartClicked()
{

    device->moveToThread(thread);

    //This will call start method of Device
    connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));

    //This will start the event loop of thread
    thread->start();
}

void Widget::onBtnStopClicked()
{
 //Tells the thread to exit
 thread->exit(0);

}

Я боюсь, что вам нужно создать подкласс QThread, если вы хотите запустить forever петля.

0 голосов
/ 05 августа 2011

ИМХО тебе не следует.Опрос требует быть в вечной петле.Вы должны сделать это в функции запуска QThread, чтобы невозможно было заново реализовать функцию без предварительного подкласса.Даже если вы попытаетесь обойти это с помощью таймера с одним выстрелом, я не рекомендую это делать.Вам лучше (вот как мне нравится это делать) подкласс QThread, вызывающий moveToThread (), а не вызов exec () и запускающий цикл навсегда.Для примера посмотрите на пример клиента блокировки Fortune из qt.Если вы не вызываете moveToThread () для QThread, тогда объект QThread все еще находится в основном потоке графического интерфейса, и они оба используют один и тот же цикл обработки событий (что плохо при использовании функций опроса).Вызов moveToThread (QThread) без вызова exec () означает, что QThread не будет иметь цикл обработки событий (что хорошо в вашем случае).Вызов exec () запускает собственный цикл обработки событий, но не используется для схем опроса, и вы бы покинули функцию run.

...