以前第一次使用线程的时候总是无法实现自己想要的效果,且为解决线程安全关闭的问题,今天看到一位老师讲了关于线程的使用方法,理解虽然还不是特别深刻,但已初步总结出相关注意事项。
环境:
- qt5.12.12
- windows操作系统
使用线程思路:
- 新建线程类,继承QThread
- 重写run()方法,将复杂程序都写在run的实现中,并设置循环条件(记得有些资料说线程必须写循环)
- 通过start()方法开启线程,通过requestInterruption()方法发出中断请求来跳出循环条件,跳出循环后该线程结束
- 在线程类中设置信号槽,当线程结束时杀死线程
- 在线程的析构函数中也要添加requestInterruption()中断请求,防止强制关闭窗口时线程不能安全关闭
先列举重要代码:(记得类要继承QThread)
AudioThread.h文件
void run() override;
AudioThread.cpp文件
//构造函数
AudioThread::AudioThread(QObject *parent) : QThread(parent)
{
// 当监听到线程结束时(finished),就调用deleteLater回收内存
connect(this,&AudioThread::finished,this,[=](){
this->deleteLater();
qDebug()<<"线程结束";
});
}
//析构函数
AudioThread::~AudioThread()
{
//强制关闭窗口时,线程也能安全关闭
requestInterruption();
wait();
qDebug()<<"析构函数";
}
void AudioThread::run()
{
.....自定义代码
while(!isInterruptionRequested()){//当没发出中断请求时,执行循环体
.....自定义代码
}
.....自定义代码
}
开启线程:
AudioThread *audio_thread=new AudioThread(this);
audio_thread->start();
关闭线程:
audio_thread->requestInterruption();
audio_thread->wait(); //等待线程结束才能执行下面代码
audio_thread=nullptr;
完整代码:(我这里是通过线程调用ffmpeg实现音频录制,看起来会有点复杂,可只关注重要代码,也不要盲目复制粘贴,运行之前需要先配置ffmpeg)
AudioThread.h文件
#ifndef AUDIOTHREAD_H #define AUDIOTHREAD_H #include#include class AudioThread : public QThread { Q_OBJECT public: explicit AudioThread(QObject *parent = nullptr); ~AudioThread(); private: void run() override; signals: }; #endif // AUDIOTHREAD_H
AudioThread.cpp文件
#include "audiothread.h" #include#include extern "C"{ // 设备相关API #include // 格式相关API #include // 工具相关API(比如错误处理) #include // 编码相关API #include } #ifdef Q_OS_WIN // PCM文件的文件名 #define FILENAME "E:/media/out.pcm" #else #define FILENAME "/Users/mj/Desktop/out.pcm" #endif AudioThread::AudioThread(QObject *parent) : QThread(parent) { // 当监听到线程结束时(finished),就调用deleteLater回收内存 connect(this,&AudioThread::finished,this,[=](){ this->deleteLater(); qDebug()<<"线程结束"; }); } AudioThread::~AudioThread() { //强制关闭窗口时,线程也能安全关闭 requestInterruption(); wait(); qDebug()<<"析构函数"; } void AudioThread::run() { char *FMT_NAME="dshow"; const AVInputFormat *localAv_find_input_format = av_find_input_format(FMT_NAME); if(!localAv_find_input_format){ qDebug()<<"找不到输入格式"< char errbuf[1024]; av_strerror(ret,errbuf,sizeof(errbuf)); qDebug()<<"打开设备失败"< qDebug()<<"文件打开失败"< //采集数据 ret = av_read_frame(ctx,pkt); if(ret==0){ //向文件中写 file.write((char *)pkt->data,pkt->size); qDebug()<<"正在录制,文件正在写入"; //释放资源 av_packet_unref(pkt); }else if (ret == AVERROR(EAGAIN)) { // 资源临时不可用 continue; } else{ char errbuf[1024]; av_strerror(ret,errbuf,sizeof(errbuf)); qDebug()<<"av_read_frame出错"< 主线程调用子线程:
void MainWindow::on_pushButton_clicked() { if(!is_record){ audio_thread=new AudioThread(this);//这里我在主文件中进行了声明AudioThread *audio_thread=nullptr; audio_thread->start(); qDebug()<<"开始录制"; ui->pushButton->setText("结束录制"); is_record=true; }else{ audio_thread->requestInterruption(); audio_thread->wait(); audio_thread=nullptr;//及时置空防止出现野指针 qDebug()<<"结束录制"; ui->pushButton->setText("开始录制"); is_record=false; } }程序效果:
感觉QThread使用起来注意事项还是比较多的,后续有新的理解会继续补充
码字不易,如果这篇博客对你有帮助,麻烦点赞收藏,非常感谢!有不对的地方



