3

あるデバイスを抽象化したクラスがあります。

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でこれを実装するにはどうすればよいですか?

4

3 に答える 3

5

一般に、スレッドの管理を誰が担当するかを決定する必要があります。それはデバイスですか、それともメイン ウィンドウですか? または、おそらくデバイスマネージャー。あなたの場合、デバイスはおそらく独自のスレッドを管理する必要があるため、サブクラス化したくない場合は、構成を使用してください。

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実際に非ブロッキングである場合にのみ機能します。後でブロッキング読み取りに切り替えることにした場合 (ほとんどの場合、これが適切でしょう)、スレッドを停止する別の方法を考え出す必要があります。

于 2011-06-16T08:11:48.287 に答える
2

このリンクを見ると、QThread をサブクラス化せずに別のスレッドでメソッドを実行できることがわかります。

ただし、あなたが求めているのは、永遠にメッセージ ループを実行することです。

与えられた例に従うと、サブクラス化せずにループを実行できますが、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 をサブクラス化する必要があります。

于 2011-06-16T08:16:01.883 に答える
0

私見、すべきではありません。ポーリングには、永久ループが必要です。QThread の run 関数でこれを行う必要があるため、最初にサブクラス化せずに関数を再実装する方法はありません。シングル ショット タイマーで回避しようとしても、お勧めしません。あなたは(これが私が好きな方法です)QThreadをサブクラス化し、moveToThread()を呼び出し、exec()を呼び出して永久ループを実行するのではありません。この例については、qt のフォーチュン ブロッキング クライアントの例を参照してください。QThread で moveToThread() を呼び出さない場合、QThread オブジェクトは引き続き GUI メイン スレッドに存在し、両方が同じイベント ループを共有します (これは、ポーリング関数を使用する場合には問題です)。exec() を呼び出さずに moveToThread(QThread) を呼び出すと、QThread にイベント ループがないことを意味します (これはあなたの場合に適しています)。

于 2011-08-04T22:15:27.800 に答える