知识点:启动进程 ,线程 ,线程同步互斥
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_OBJECT
public:
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_OBJECT
void 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)
{
//lock
qDebug()<<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() == 5
sem.acquire(3); // sem.available() == 2
sem.acquire(2); // sem.available() == 0
sem.release(5); // sem.available() == 5
sem.release(5); // sem.available() == 10
sem.tryAcquire(1); // sem.available() == 9, returns true
sem.tryAcquire(250); // sem.available() == 9, returns false
QMutex ://locker
QMutex 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);
//V
sem->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)
{
//P
sem->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_OBJECT
public:
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 0
for(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 发送信号