1. 程式人生 > >Qt QThread 執行緒建立,執行緒同步,執行緒通訊 例項

Qt QThread 執行緒建立,執行緒同步,執行緒通訊 例項

1.  繼承QThread, 實現run()方法, 即可建立執行緒。

2. 例項1 程式碼

myThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class myThread : public QThread   //myThread 執行緒類
{
    Q_OBJECT

public:
    myThread();
    void setMessage(const QString &message);
    void stop();
protected:
    void run();   //複寫run()方法,裡面是執行緒 的 主體程式碼
private:
    QString messageStr;
    volatile bool stopped;
};

#endif // MYTHREAD_H

myThread.cpp

#include "myThread.h"
#include <QDebug>

myThread::myThread()
{
    stopped = false;
}

void myThread::run()  //實現run()方法, 隔1秒輸出messageStr
{
    while(!stopped)
    {
        qDebug() << messageStr << endl;
        sleep(1);
    }
    stopped = false;
}

void myThread::stop()
{
    stopped = true;
}

void myThread::setMessage(const QString &message)
{
    messageStr = message;
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QtGui>
#include "myThread.h"

class Dialog : public QDialog
{
    Q_OBJECT
    
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

protected:
    void closeEvent(QCloseEvent *event);

private slots:
    void startOrStopThreadA();
    void startOrStopThreadB();

private:
    myThread threadA;   //用執行緒類 例項化 執行緒物件
    myThread threadB;
    QPushButton *threadAButton;
    QPushButton *threadBButton;
    QPushButton *quitButton;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{    
    threadA.setMessage("A");
    threadB.setMessage("B");

    threadAButton = new QPushButton(tr("Start A"));
    threadBButton = new QPushButton(tr("Start B"));
    quitButton = new QPushButton(tr("Quit"));
    quitButton->setDefault(true);
    connect(threadAButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadA()));
    connect(threadBButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadB()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

    QHBoxLayout *hLayout = new QHBoxLayout;
    hLayout->addWidget(threadAButton);
    hLayout->addWidget(threadBButton);
    hLayout->addWidget(quitButton);
    setLayout(hLayout);
}

Dialog::~Dialog()
{    
}

void Dialog::startOrStopThreadA()
{
    if( threadA.isRunning() )
    {
        threadA.stop();   //結束執行緒
        threadAButton->setText(tr("Start A"));
    }
    else
    {
        threadA.start();   //thread.start()開始執行緒
        threadAButton->setText(tr("Stop A"));
    }
}

void Dialog::startOrStopThreadB()
{
    if( threadB.isRunning() )
    {
        threadB.stop();
        threadBButton->setText(tr("Start B"));
    }
    else
    {
        threadB.start();
        threadBButton->setText(tr("Stop B"));
    }
}

void Dialog::closeEvent(QCloseEvent *event)  //當用戶點選quit按鍵  或 這退出UI的時候,回撥closeEvent函式
{
    threadA.stop();
    threadB.stop();
    threadA.wait();
    threadB.wait();
    event->accept();
    //qDebug("--log--");
}


3. 執行緒同步

QT執行緒同步的類有: QMutex, QReadWriteLock, QSemaphore, QWaitcondition.

QMutext互斥鎖: 可以鎖住一段程式碼,同一時間只能有一個執行緒訪問。

或者用簡化鎖QMutexLocked類, 建構函式輸入QMutex並將其鎖住, 解構函式將其解鎖。

QReadWriteLock類, 允許多個執行緒讀共享資源,但是隻允許一個執行緒寫共享資源。


QSemaphore 訊號量 互斥量, 解決 生產者--消費者 問題



 

4. 利用訊號槽, 主執行緒和子執行緒通訊,互相傳送訊息。

子執行緒向主執行緒傳送 每隔一秒向主執行緒傳送累加數字, 主執行緒按鍵資訊傳送到子執行緒。。

Thread.h

#ifndef THREAD_H
#define THREAD_H
#include <QThread>

class Thread : public QThread
{
    Q_OBJECT
private:
    int number;
protected:
    void run();
public:
    Thread(QObject *parent=0);
    ~Thread();
signals:
    void UpdateSignal(int num);
public slots:
    void ResetSlot();
};

#endif // THREAD_H

Thread.cpp

#include "Thread.h"

Thread::Thread(QObject *parent)
{
    number = 0;
}

Thread::~Thread()
{
}

void Thread::run()
{
    while(1)
    {
        emit UpdateSignal(number);  //傳送更新訊號給主執行緒,附帶引數number
        number++;
        sleep(1);
    }
}

void Thread::ResetSlot()
{
    number = 0;
    emit UpdateSignal(number);  //傳送重置number訊號
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui>
#include "Thread.h"

class Widget : public QWidget
{
    Q_OBJECT
    
public:
    Widget(QWidget *parent = 0);
    ~Widget();

private:
    QLabel *label;
    QPushButton *startButton;
    QPushButton *stopButton;
    QPushButton *resetButton;
    Thread *myThread;
    int number;

signals:
    void ResetSignal();

public slots:
    void clearSlot();
    void startSlot();
    void stopSlot();
    void updateSlot(int num);

};

#endif // WIDGET_H

widget.cpp

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    startButton = new QPushButton("start");
    stopButton = new QPushButton("stop");
    resetButton = new QPushButton("reset");
    label = new QLabel("empty");

    myThread = new Thread();

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(label);
    layout->addWidget(startButton);
    layout->addWidget(stopButton);
    layout->addWidget(resetButton);
    setLayout(layout);

    connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSlot()));
    connect(startButton, SIGNAL(clicked()), this, SLOT(startSlot()));
    connect(resetButton, SIGNAL(clicked()), this, SLOT(clearSlot()));
    connect(myThread, SIGNAL(UpdateSignal(int)), this, SLOT(updateSlot(int)));   //子執行緒發訊號給主執行緒,更新number
    connect(this, SIGNAL(ResetSignal()), myThread, SLOT(ResetSlot()));   //主執行緒發訊號給子執行緒,重置number訊號

    resize(200, 200);

}

Widget::~Widget()
{
    
}

void Widget::startSlot()
{
    myThread->start();
}

void Widget::stopSlot()
{
    myThread->terminate();
}

void Widget::updateSlot(int num)
{
    label->setText(QString::number(num));
}

void Widget::clearSlot()
{
    emit ResetSignal();     //主執行緒傳送重置訊號 給 子執行緒
}