Qt多线程的坑: Timers cannot be started from another thread

今天用qt5写多线程的时候遇到了一个报错Timers cannot be started from another thread,意思是我在一个线程中创建了QTimer对象,不能在另一个线程中start()该对象。

但是我觉得很奇怪,因为我的类中没有一个成员是QTimer或者其子类的,搞了半天才反应起来,可能是隐式的QTimer对象,也就是说,Qt内部在实现某种功能的时候使用了QTimer对象的start方法。
 

1.改法:

 在我的代码中,我自定义一个AudioInput类,并在构造函数中new了一个audio对象,audio对象是一个QAudioInput类的对象。

在另一个类Widget的构造函数中我创建了new了一个AudioInput类的对象_ainput,并且使用moveToThread()将其放到一个新的子线程中执行。于是我发现,当我在

void AudioInput::startCollect()
{
    inputdevice = audio->start();
    connect(inputdevice, &QIODevice::readyRead, this, &AudioInput::onreadyRead);
}

函数中调用 inputdevice = audio->start();时就报错了 Timers cannot be started from another thread

这是原来的代码

AudioInput::AudioInput(QObject *parent)
        : QThread(parent)
{
        // 设置音频格式
        format.setSampleRate(8000);
        format.setChannelCount(1);
        format.setSampleSize(8);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::UnSignedInt);

        audio = new QAudioInput(format, this);
        connect(audio,SIGNAL(stateChanged(QAudio::State)),
        this,SLOT(handleStateChanged(QAudio::State)));

        //测试
        QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
        foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
            if (deviceInfo.deviceName().contains("input.pci")) {
                info = deviceInfo;
                break;
            }
        }
        if (!info.isFormatSupported(format)) {

            qWarning() << "Audio Input Format Useless!!!!!!!!!!!";
            format = info.nearestFormat(format);
        }


}

void AudioInput::startCollect()
{
    inputdevice = audio->start();
    connect(inputdevice, &QIODevice::readyRead, this, &AudioInput::onreadyRead);
}
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{

    //音频
    _ainput = new AudioInput();
    _ainputThread = new QThread();
    _ainput->moveToThread(_ainputThread);
    _ainputThread->start();

    QPushButton* button1 = new QPushButton(this);
    button1->setText("开始录音");
    QPushButton* button2 = new QPushButton(this);
    button2->setText("结束录音");
    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(button1);
    mainLayout->addWidget(button2);

    connect(button1, &QPushButton::clicked, _ainput, &AudioInput::startCollect);
    connect(button2, &QPushButton::clicked, _ainput, &AudioInput::stopCollect);

    resize(200,150);
}

这是修改之后的代码,主要的部分就是将AudioInput类的构造函数中本来new的audio对象放到了

startCollect函数中去new

AudioInput::AudioInput(QObject *parent)
        : QThread(parent)
{
        // 设置音频格式
        format.setSampleRate(8000);
        format.setChannelCount(1);
        format.setSampleSize(8);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::UnSignedInt);

        audio = nullptr;            //修改之后的部分

        //测试
        QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
        foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
            if (deviceInfo.deviceName().contains("input.pci")) {
                info = deviceInfo;
                break;
            }
        }
        if (!info.isFormatSupported(format)) {

            qWarning() << "Audio Input Format Useless!!!!!!!!!!!";
            format = info.nearestFormat(format);
        }


}

void AudioInput::startCollect()
{
    // 需要把audio的创建放到子线程中
    if (audio == nullptr) {                    //修改之后的部分
        qDebug() << "正在初始化";
        audio = new QAudioInput(format, this);
        connect(audio, SIGNAL(stateChanged(QAudio::State)),
            this, SLOT(handleStateChanged(QAudio::State)));
    }
    qDebug() << "初始化完成";
    inputdevice = audio->start();
    connect(inputdevice, &QIODevice::readyRead, this, &AudioInput::onreadyRead);
}

2.原理

之前已经提到过,这个报错的本质就是在一个线程中创建了QTimer对象,但是在另一个线程中start这个对象,我之前的代码中,是在主线程中创建的QAudioInput对象,然后把其整个父类AudioInput对象放到了一条新的线程中,然后才使用信号触发了其槽函数,调用QAudioInput对象的start函数,因此报错,所以只要将创建和start函数的调用都放在同一个线程(新的线程)中就好了。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值