qt_线程

线程

线程分为gui线程(主线程)和次要线程,涉及gui的必须在主线程

线程的同步

两个线程可以同时访问一个对象,试想如果一个对象同时执行两种方法则可能出错
QMutex 是强制执行互斥的基本类。一个线程锁定一个互斥量(mutex),以获得共享资源的访问权限。如果另一个线程试图锁定互斥量,而互斥量已被锁定,这时,它将进入睡眠状态,直到第一个线程完成其任务并解锁互斥量。

QReadWriteLock 类似于 QMutex,除了它区分了“读”和“写”的访问。当一个数据块没有被写入,多线程对他同时进行读取是安全的。一个 QMutex 迫使轮流读取共享数据,而 QReadWriteLock 允许同时读取,从而提高并行性。
QSemaphore 是 QMutex 的一个推广,可以保护一定数量相同的资源。相比之下,一个 QMutex 只能保护一个资源
QWaitCondition 同步线程,不通过执行互斥,而通过提供一个条件变量。其它原语使线程等待,直到资源被解锁
QMutexLocker、QReadLockerQWriteLocker 是便利类,使其更易于使用 QMutex 和QReadWriteLock 。当他们被构建时,就会锁定资源;当被销毁时,就会自动解锁。设计他们是为了简化使用 QMutex 和 QReadWriteLock 的代码,从而减少资源被永久锁定的可能性。

线程安全的可重入类
注意点:
1.事件的驱动对象只能被使用在单线程中,也就是不能在此线程中引用别的线程的socket或者定时器之类的
2.gui类是不可重入的,只能放在主线程中

class Counter
{
public:
    Counter() { n = 0; }

    void increment() { QMutexLocker locker(&mutex); ++n; }//局部变量locker销毁时mutex被释放相当于unlock了
    void decrement() { QMutexLocker locker(&mutex); --n; }
    int value() const { QMutexLocker locker(&mutex); return n; }

private:
    mutable QMutex mutex;//由于const,所以加mutable,可修改
    int n;
};

**QObject::moveToThread()**函数改变一个对象和它的孩子的线程所属性。
从另一个线程(不是该QObject对象所属的线程)对该QObject对象调用delete方法是不安全的,除非你能保证该对象在那个时刻不处理事件,使用QObejct::deleteLater()更好。一个DeferredDelete类型的事件将被提交(posted),而该对象的线程的事件循环最终会处理这个事件。默认情况下,拥有一个QObject的线程就是创建QObject的那个线程,而不是QObject::moveToThread()被调用后的。
QCoreApplication::postEvent(),你可以在任何时刻给任何线程中的任何对象发送事件,这些事件将自动被分发到该对象所被创建的线程事件循环中。
**QCoreApplication::sendEvent()**不同于postEvent())只能将事件分发到和该函数调用者相同的线程中的对象。
可以在QThread::run()的实现中安全地发射信号,因为信号发射是线程安全的或者必须用一个mutex保护对该QObject子类的内部数据的所有访问

QtConcurrent

该QtConcurrent命名空间提供高层次的API,使人们可以编写多线程程序,而无需使用低级线程原语。
Header: #include
qmake: QT += concurrent

/*
*QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strlist, allLowerCase);//返回序列
* QtConcurrent::blockingFilter(strlist, allLowerCase);//直接修改
*/
bool allLowerCase(const QString &str)
{
    return str.toLower()==str;
}
void addToDictionary(QString &dictionary, const QString &string)
{
     dictionary.append(string);
}
GuiTest::GuiTest(QWidget *parent)
    : QMainWindow(parent)
{
    QStringList strlist;
    strlist<<"zylg1"<<"zylg2"<<"123"<<"ZYLG"<<"Zylg";
    foreach(QString str ,strlist)cout<<str<<"\t";cout<<endl;
    QStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strlist, allLowerCase);//返回序列
    QFuture<QString> dictionary = QtConcurrent::filteredReduced(strlist, allLowerCase, addToDictionary);
    QtConcurrent::blockingFilter(strlist, allLowerCase);//直接修改
    foreach(QString str ,strlist)cout<<str<<"\t";cout<<endl;
    foreach(QString str ,lowerCaseStrings)cout<<str<<"\t";cout<<endl;
    foreach(QString str ,dictionary)cout<<str<<"\t";cout<<endl;
}
/*
 * result:
 * zylg1	zylg2	123	ZYLG	Zylg	
 * zylg1	zylg2	123	
 * zylg1	zylg2	123	
 * zylg1zylg2123	
*/
QImage scaled(const QImage &image)
{
    return image.scaled(100, 100);
}

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);
//void QtConcurrent::blockingMap(Iterator begin, Iterator end, MapFunctor function)
//QList<int> ints = QtConcurrent::blockingMapped<QList<int> >(beginIterator, endIterator, fn);
#include<QTextStream>
#include<QtConcurrent>
#include<QString>
#include<QSet>
#include<QFuture>
#include<iterator>
#include<QFile>
#include<QDir>
#include<QList>
#include<QTime>
QTextStream cout(stdout);
//递归搜索文件
QStringList findFiles(const QString &startDir, QStringList filters)
{
    QStringList names;
    QDir dir(startDir);

    foreach (QString file, dir.entryList(filters, QDir::Files))
        names += startDir + '/' + file;

    foreach (QString subdir, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot))
        names += findFiles(startDir + '/' + subdir, filters);
    return names;
}
// 单线程统计文件大小
qint64 singleThreadedSize(QStringList files)
{
    qint64 folder_size=0;
    foreach (QString file, files) {
        QFile f(file);
        folder_size+=f.size();
    }
    return folder_size;
}
//计算单个文件大小,用于线程并发
qint64 fileSize(const QString &file)
{
    QFile f(file);
    return f.size();
}
//统计总的大小,用于线程并发结果的处理
void sumSize(qint64 &sumsize,const qint64 &size)
{
    sumsize+=size;
}

GuiTest::GuiTest(QWidget *parent)
    : QMainWindow(parent)
{
    qDebug()<<"find files ...";
    QStringList file_list=findFiles("/home/zz",QStringList()<<"*.*");
//    foreach (QString str, file_list) {
//        cout<<str<<endl;
//    }
    int single_thread_time=0;
    {
       QTime time;
       time.start();
       qint64 folder_size=singleThreadedSize(file_list);
       single_thread_time=time.elapsed();
       cout<<"singke Time is :"<<single_thread_time<<endl<<"size is:"<<folder_size/1024/1024<<"M"<<endl;
    }
    int concurrent_thread_time=0;
    {
        QTime time;
        time.start();
        qint64 folder_size2=QtConcurrent::mappedReduced(file_list,fileSize,sumSize);
        concurrent_thread_time=time.elapsed();
        cout<<"concurrut Time is :"<<concurrent_thread_time<<endl<<"size is:"<<folder_size2/1024/1024<<"M"<<endl;
    }
    qDebug()<<(double)single_thread_time/concurrent_thread_time;
}
/*
 * result:
 * find files ...
 * singke Time is :76
 * size is:1927M
 * concurrut Time is :34
 * size is:1927M
 * 2.23529
*/

QtConcurrent::run() 函数在一个单独的线程中运行一个函数, 函数的返回值通过 QFuture API 提供。

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);
QTextStream cout(stdout);
//递归搜索文件
QStringList findFiles(const QString &startDir, QStringList filters)
{
    QStringList names;
    QDir dir(startDir);

    foreach (QString file, dir.entryList(filters, QDir::Files))
        names += startDir + '/' + file;

    foreach (QString subdir, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot))
        names += findFiles(startDir + '/' + subdir, filters);
    return names;
}
// 单线程统计文件大小
qint64 singleThreadedSize(QStringList files)
{
    qint64 folder_size=0;
    foreach (QString file, files) {
        QFile f(file);
        folder_size+=f.size();
    }
    return folder_size;
}
GuiTest::GuiTest(QWidget *parent)
    : QMainWindow(parent)
{
    QStringList filter;
    filter<<"*.*";
    QString dir("/home/zz");
    QFuture<QStringList> strlistfu=QtConcurrent::run(findFiles,dir,filter);
    QStringList strlist=strlistfu.result();
    QFuture<qint64> sizefu=QtConcurrent::run(singleThreadedSize,strlist);//启动一个线程
    //QFuture 获取一步计算的结果,有个迭代器
    qint64 size=sizefu.result()/1024/1024;
    QTextBrowser *texbrowser=new QTextBrowser;
    texbrowser->append(QString("%0M").arg(size));
    texbrowser->resize(500,500);
    texbrowser->show();
}
/*
 *1927M
*/

QFutureWatcher监视QFuture

函数 作用
QFuture future() const
bool isCanceled() const
bool isFinished() const
bool isPaused() const
bool isRunning() const
bool isStarted() const
int progressMaximum() const
int progressMinimum() const
QString progressText() const
int progressValue() const
T result() const
T resultAt(int index) const
void setFuture(const QFuture &future)
void setPendingResultsLimit(int limit)
void waitForFinished()

slots:
void cancel()
void pause()
void resume()
void setPaused(bool paused)
void togglePaused()

signals:
void canceled()
void finished()
void paused()
void progressRangeChanged(int minimum, int maximum)
void progressTextChanged(const QString &progressText)
void progressValueChanged(int progressValue)
void resultReadyAt(int index)
void resultsReadyAt(int beginIndex, int endIndex)
void resumed()
void started()

// 实例化对象,并连接到 finished() 信号。
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

// 开始计算
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);
// 连接信号槽 - 加载、显示进度、打开、取消等操作
    connect(m_pWatcher, SIGNAL(resultReadyAt(int)), SLOT(showImage(int)));
    connect(m_pWatcher, SIGNAL(progressRangeChanged(int,int)), pProgressBar, SLOT(setRange(int,int)));
    connect(m_pWatcher, SIGNAL(progressValueChanged(int)), pProgressBar, SLOT(setValue(int)));
    connect(m_pWatcher, SIGNAL(finished()), SLOT(finished()));

QThread

函数 作用
void exit(int returnCode = 0) 退出
bool isFinished() const 是否完成
bool isInterruptionRequested() const
bool isRunning() const 是否运行
int loopLevel() const
Priority priority() const 优先级
void requestInterruption()
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
void setPriority(Priority priority) 优先级
void setStackSize(uint stackSize)
uint stackSize() const
bool wait(unsigned long time = ULONG_MAX)
QThread * currentThread() 目前线程
Qt::HANDLE currentThreadId()
int idealThreadCount()
void msleep(unsigned long msecs)
void sleep(unsigned long secs)

slots:
quit()
start(Priority priority = InheritPriority)
terminate()

signals:
void finished()
void started()

protected function:
int exec()
virtual void run()

class WorkerThread : public QThread
{
    Q_OBJECT
    void run() override {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
signals:
    void resultReady(const QString &s);
};

void MyObject::startWorkInAThread()
{
    WorkerThread *workerThread = new WorkerThread(this);
    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    workerThread->start();
}
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include<QThread>
#include<QMutexLocker>
#include<QDebug>
class MyThread:public QThread
{
    Q_OBJECT
public:
    MyThread(QObject *parent=0):QThread(parent)
    {
        qDebug()<<"thread is created";
        m_bStopped=false;
    }
    ~MyThread()
    {
        stop();
        quit();
        wait();
    }
    void stop()
    {
        qDebug()<<"thread stop:"<<QThread::currentThreadId();
        QMutexLocker locker(&m_mutex);
        m_bStopped=true;
    }
   void run()
    {
       m_bStopped=false;
       qDebug()<<"thread runing"<<QThread::currentThreadId();
       int value=0;
       while(value<100)
       {
           msleep(50);//休眠50毫秒
           ++value;
           qDebug()<<value;
           emit resultReady(value);
           {
               QMutexLocker locker(&m_mutex);
               if(m_bStopped)break;
           }
           if(value>=100 && m_bStopped==false)value=0;
           if(m_bStopped==true)break;
       }
    }

private:
    bool m_bStopped;
    QMutex m_mutex;

signals:
    void resultReady(int);
public slots:
    void setPause()
    {
        m_bStopped=true;
    }
};

#endif // MYTHREAD_H


QTextStream cout(stdout);
GuiTest::GuiTest(QWidget *parent)
    : QMainWindow(parent)
{


    QWidget *wid=new QWidget();
    this->setCentralWidget(wid);
    QVBoxLayout *main_layout=new QVBoxLayout(wid);
    QHBoxLayout *layout=new QHBoxLayout();
    QPushButton *start_bt=new QPushButton("start",wid);
    QPushButton *canel_bt=new QPushButton("canel",wid);
    layout->addStretch();
    layout->addWidget(start_bt);
    layout->addStretch();
    layout->addWidget(canel_bt);
    layout->addStretch();
    QProgressBar *m_probar=new QProgressBar(wid);
    m_probar->setRange(0,100);
    m_probar->setValue(0);
    main_layout->setContentsMargins(10,20,20,20);
    main_layout->addWidget(m_probar);
    main_layout->setSpacing(20);
    main_layout->addLayout(layout);
    this->resize(500,400);

    //=============上面为布局,现在开始调用线程,控制m_probar的value========
    connect(start_bt,QOverload<bool>::of(&QPushButton::clicked),[m_probar,canel_bt]{
       MyThread *thread=new MyThread();
       connect(canel_bt,SIGNAL(clicked(bool)),thread,SLOT(setPause()));
       connect(thread,QOverload<int>::of(&MyThread::resultReady),[m_probar](int val){
           m_probar->setValue(val);

       });
       thread->start();
    });
    this->show();
}

猜你喜欢

转载自blog.csdn.net/qq_33564134/article/details/84971426