一、基于信号量的线程同步
信号量通常用于保护一定数量的相同资源,如数据采集时的双缓冲区
- acquire(int n)尝试获得N个资源,如果没有那么多资源,线程将阻塞直到有n个资源可用
- release(int n)释放n个资源,如果信号量的资源已全部可用之后再releas(),就可以创建更多的资源,增加可用资源的个数
- int available()返回当前信号量可用资源个数,这个数不可能为负数,如果为0就说明当前没有资源可用
- bool tryAcquire(int n=1)尝试获取n个资源,不成功时不阻塞线程
二、多线程
1.方法1
1.1.创建一个线程类的子类,让其继承 QT 中的线程类 QThread
class Generate : public QThread
explicit Generate(QObject *parent = nullptr);
protected:
void run() override;
Generate::Generate(QObject *parent) : QThread(parent)
{
}
qDebug() << "生成随机数的线程地址: " << QThread::currentThread();
QVector<int> list;
QElapsedTimer time;
time.start();
for(int i=0;i<m_num;i++)
{
list.push_back(qrand()%10000);
}
int milsec = time.elapsed();//从启动或重启用时
qDebug() << "生成" << m_num << "个随机数总共用时: " << milsec << "毫秒";
1.2.重写父类的 run () 方法,在该函数内部编写子线程要处理的具体的业务流程
1.3.在主线程中创建子线程对象,new 一个就可以了
1.4.启动子线程,调用 start () 方法
1.5对线程的析构
connect(this,&MainWindow::destroyed,this,[=](){
gen->quit();
gen->wait();
gen->deleteLater(); // delete gen;
bubble->quit();
bubble->wait();
bubble->deleteLater();
quick->quit();
quick->wait();
quick->deleteLater();
});
2.方法2
2.1创建一个新的类,让这个类从 QObject 派生
class Generate:public QObject{}
2.1在这个类中添加一个公共的成员函数,函数体就是我们要子线程中执行的业务逻辑
public:
void working();
2.3在主线程中创建一个 QThread 对象,这就是子线程的对象
QThread *t1=new QThread;
2.4在主线程中创建工作的类对象(千万不要指定给创建的对象指定父对象)
Generate *gen=new Generate;
2.5将 MyWork 对象移动到创建的子线程对象中,需要调用 QObject 类提供的 moveToThread() 方法
gen->moveToThread(t1);
2.6启动子线程,调用 start(), 这时候线程启动了,但是移动到线程中的对象并没有工作
t1->start();
2.7调用 MyWork 类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的
connect(ui->btnStart,&QPushButton::clicked,gen,&Generate::working);
2.8 同上1.5删除线程
3.方法3
3.1先创建任务
//添加到线程池中的每一个任务都需要是一个 QRunnable 类型,因此在程序中需要创建子类继承 QRunnable 这个类,同时如果有使用信号槽进行数据传递,需要继承QObject
class Generate:public QObject,public QRunnable
//-------------------------------------------------------------------
Generate::Genrate(QObject *parent):QObject(parent),QRunnable(){
//任务执行完毕,该对象自动销毁
setAutoDelete(true);
}
3.2 重写run方法,在这个函数中编写要在线程池中执行的任务
3.3线程池初始化,设置最大线程池数
QThreadPool::globalInstance()->setMaxThreadCount(4);
3.4 创建工作线程对象
Generate *genThread=new Generate;
3.5将工作对象扔进线程池启动
QThreadPool::globalInstance()->start(genThread);
// 在子类中必须要重写的函数, 里边是任务的处理流程
[pure virtual] void QRunnable::run();
// 参数设置为 true: 这个任务对象在线程池中的线程中处理完毕, 这个任务对象就会自动销毁
// 参数设置为 false: 这个任务对象在线程池中的线程中处理完毕, 对象需要程序猿手动销毁
void QRunnable::setAutoDelete(bool autoDelete);
// 获取当前任务对象的析构方式,返回true->自动析构, 返回false->手动析构
bool QRunnable::autoDelete() const;
// 获取和设置线程中的最大线程个数
int maxThreadCount() const;
void setMaxThreadCount(int maxThreadCount);
// 给线程池添加任务, 任务是一个 QRunnable 类型的对象
// 如果线程池中没有空闲的线程了, 任务会放到任务队列中, 等待线程处理
void QThreadPool::start(QRunnable * runnable, int priority = 0);
// 如果线程池中没有空闲的线程了, 直接返回值, 任务添加失败, 任务不会添加到任务队列中
bool QThreadPool::tryStart(QRunnable * runnable);
// 线程池中被激活的线程的个数(正在工作的线程个数)
int QThreadPool::activeThreadCount() const;
// 尝试性的将某一个任务从线程池的任务队列中删除, 如果任务已经开始执行就无法删除了
bool QThreadPool::tryTake(QRunnable *runnable);
// 将线程池中的任务队列里边没有开始处理的所有任务删除, 如果已经开始处理了就无法通过该函数删除了
void QThreadPool::clear();
// 在每个Qt应用程序中都有一个全局的线程池对象, 通过这个函数直接访问这个对象
static QThreadPool * QThreadPool::globalInstance();