知识点:启动进程 ,线程 ,线程同步互斥
1 启动进程
应用场景:通常在qt中打开另一个程序
process模板
QString program = “/bin/ls";
QStringList arguments;
arguments << "-l" << “-a";QProcess *myProcess = new QProcess(parent);
myProcess->execute(program, arguments);
示例:
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QFileDialog>
#include <QProcess>
#include <QStringList>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();
public slots:void showfile(){QString filename = QFileDialog::getOpenFileName();le->setText(filename);QStringList arg = {filename};QProcess ppp;ppp.execute("notepad", arg);}private:QLineEdit *le;QPushButton *pb;
};#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QVBoxLayout>Widget::Widget(QWidget *parent): QWidget(parent)
{le = new QLineEdit;pb = new QPushButton("showtxt");QVBoxLayout *vbox = new QVBoxLayout;vbox->addWidget(le);vbox->addWidget(pb);setLayout(vbox);connect(pb, SIGNAL(clicked(bool)), this, SLOT(showfile()));
}Widget::~Widget()
{}
效果在qt中使用文本编辑器打开一个文本。
2 线程
应用场景:启动一个线程和进程来辅助程序
线程:
class WorkerThread : public Qthread{
Q_OBJECTvoid run() {/* ... here is the expensive or blocking operation ... */emit resultReady(result);}
signals:void resultReady(const QString &s);};
WorkerThread x;
x.start();
-
void run()
方法:这是QThread
的一个虚函数,你需要在子类中重写它以实现线程的任务。当调用线程的start()
方法时,这里的代码将在新的线程中执行。 -
void resultReady(const QString &s)
信号:这是一个自定义信号,当线程完成工作并有结果可供返回时,将通过emit
关键字发射这个信号。 -
QT是信号驱动、或者异步驱动的框架,平时app需要执行到a.exec()才会执行
双线程示例:一个线程打印数组,一个线程排序数组
thread_show.h(继承QThread类)
#ifndef THREAD_SHOW_H
#define THREAD_SHOW_H#include <Qthread>
#include <QDebug>
#include <QMutex>class thread_show : public QThread
{Q_OBJECT
public:thread_show(char *p):m_arr(p){}void run() //这是QThread的一个虚函数(qt中斜线表示),你需要在子类中重写它以实现线程的任务。当调用线程的start()方法时,这里的代码将在新的线程中执行。{while(1){//lockqDebug()<<m_arr;sleep(1);}}
private:char *m_arr;};#endif // THREAD_SHOW_H
thread_show.cpp(重写构造函数)
#include "thread_show.h"/*
thread_show::thread_show()
{}
*/
thread_rev.h
#ifndef THREAD_REV_H
#define THREAD_REV_H#include <QThread>class thread_rev : public QThread
{Q_OBJECT
public:thread_rev(char *p):m_arr(p){} //构造时,直接赋值效率高void run(){while(1){for(int i=0; i<5; i++){m_arr[i] ^= m_arr[9-i];m_arr[9-i] ^= m_arr[i];m_arr[i] ^= m_arr[9-i];}}}
private:char *m_arr;
};#endif // THREAD_REV_H
thread_rev.cpp(重写构造函数)
#include "thread_rev.h"/*
thread_rev::thread_rev()
{}
*/
main.cpp
#include "widget.h"
#include <QApplication>
#include "thread_rev.h"
#include "thread_show.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);char arr[] = "0123456789";thread_show t1(arr); //打印thread_rev t2(arr); //翻转数组t1.start();t2.start();return a.exec();
}
效果:两个线程同时操作,打印出来的数组无规律
3 线程互斥
官方示例
QSemaphore :QSemaphore sem(5); // sem.available() == 5sem.acquire(3); // sem.available() == 2sem.acquire(2); // sem.available() == 0sem.release(5); // sem.available() == 5sem.release(5); // sem.available() == 10sem.tryAcquire(1); // sem.available() == 9, returns truesem.tryAcquire(250); // sem.available() == 9, returns falseQMutex ://lockerQMutex mutex;void method1(){mutex.lock();mutex.unlock();}void method2(){mutex.lock();mutex.unlock();}
实验示例:
thread_show.h
#ifndef THREAD_SHOW_H
#define THREAD_SHOW_H#include <Qthread>
#include <QDebug>
#include <QMutex>class thread_show : public QThread
{Q_OBJECT
public:thread_show(char *p, QMutex *l):m_arr(p), m_arrlock(l){}void run() //这是QThread的一个虚函数(qt中斜线表示),你需要在子类中重写它以实现线程的任务。当调用线程的start()方法时,这里的代码将在新的线程中执行。{while(1){m_arrlock->lock();qDebug()<<m_arr;m_arrlock->unlock();sleep(1);}}
private:char *m_arr;QMutex *m_arrlock;};#endif // THREAD_SHOW_H
thread_show.cpp
#include "thread_show.h"/*
thread_show::thread_show()
{}
*/
thread_rev.h
#ifndef THREAD_REV_H
#define THREAD_REV_H#include <QThread>
#include <QMutex>class thread_rev : public QThread
{Q_OBJECT
public:thread_rev(char *p, QMutex *l):m_arr(p), m_arrlock(l){}void run(){while(1){m_arrlock->lock();for(int i=0; i<5; i++){m_arr[i] ^= m_arr[9-i];m_arr[9-i] ^= m_arr[i];m_arr[i] ^= m_arr[9-i];}m_arrlock->unlock();}}
private:char *m_arr;QMutex *m_arrlock;};#endif // THREAD_REV_H
thread_rev.cpp
#include "thread_rev.h"/*
thread_rev::thread_rev()
{}
*/
main.cpp
#include "widget.h"
#include <QApplication>
#include "thread_rev.h"
#include "thread_show.h"
#include <QMutex>int main(int argc, char *argv[])
{QApplication a(argc, argv);char arr[] = "0123456789";QMutex arr_lock;thread_show t1(arr,&arr_lock); //打印thread_rev t2(arr,&arr_lock); //翻转数组t1.start();t2.start();return a.exec();
}
效果:两个线程同时操作,打印出来的数组均为排序后的结果,排序中不会受到干扰
4 线程同步
目的:实现一个线程获取资源需要等另一个线程释放资源。
thread_hello.h
#ifndef THREAD_HELLO_H
#define THREAD_HELLO_H#include <QSemaphore>
#include <QThread>
#include <QDebug>class thread_hello : public QThread
{Q_OBJECT
public:thread_hello(QSemaphore *s):sem(s){ }void run(){while(1){qDebug()<<"hello";sleep(1);//Vsem->release();}}
private:QSemaphore *sem;
};#endif // THREAD_HELLO_H
thread_hello.cpp
#include "thread_hello.h"/*
thread_hello::thread_hello()
{}
*/
thread_world.h
#ifndef THREAD_WORLD_H
#define THREAD_WORLD_H#include <QThread>
#include <QDebug>
#include <QSemaphore>class thread_world : public QThread
{Q_OBJECT
public:thread_world(QSemaphore *s):sem(s){ }void run() //字体歪的就是虚函数{while(1){//Psem->acquire();qDebug()<<"world";}}
private:QSemaphore *sem;
};#endif // THREAD_WORLD_H
thread_world.cpp
#include "thread_hello.h"/*
thread_hello::thread_hello()
{}
*/
main.cpp
#include <QCoreApplication>
#include "thread_hello.h"
#include "thread_world.h"
#include <QSemaphore>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QSemaphore sem;thread_hello hello(&sem);thread_world world(&sem);hello.start();world.start();return a.exec();
}
效果,hello先打印,才会有world。
综合示例:实现两个进度条在下载
mythread1.h
#ifndef MYTHREAD1_H
#define MYTHREAD1_H#include <QThread>class myThread1 : public QThread
{Q_OBJECT
signals:downloaded(int);
public:myThread1();void run(){for(int i=0;i<100; i++){//p1->setValue(i);emit downloaded(i);QThread::sleep(2);}}
};#endif // MYTHREAD1_H
mythread1.cpp
#include "mythread1.h"myThread1::myThread1()
{}
mythread2.h
#ifndef MYTHREAD2_H
#define MYTHREAD2_H#include <QThread>class myThread2 : public QThread
{Q_OBJECT
signals:downloaded(int);
public:myThread2();void run(){for(int i=0;i<100; i++){//p1->setValue(i);emit downloaded(i);QThread::sleep(1);}}
};#endif // MYTHREAD2_H
mythread1.cpp
#include "mythread2.h"myThread2::myThread2()
{}
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QProgressBar>
#include "mythread2.h"
#include "mythread1.h"class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();
private:QProgressBar *p1, *p2;myThread1 *t1;myThread2 *t2;
};#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QVBoxLayout>
#include <QThread>Widget::Widget(QWidget *parent): QWidget(parent)
{p1 = new QProgressBar;p2 = new QProgressBar;QVBoxLayout *vbox = new QVBoxLayout;vbox->addWidget(p1);vbox->addWidget(p2);setLayout(vbox);t1 = new myThread1;t2 = new myThread2;connect(t1, SIGNAL(downloaded(int)), p1, SLOT(setValue(int)));connect(t2, SIGNAL(downloaded(int)), p2, SLOT(setValue(int)));t1->start();t2->start();#if 0for(int i=0;i<100; i++){p1->setValue(i);QThread::sleep(1);}for(int i=0;i<100; i++){p2->setValue(i);QThread::sleep(2);}
#endif
}Widget::~Widget()
{}
注:
downloaded(不需要实现,qt实现的不是函数)
emit发送一个信号
exit 发送信号