QT 4.8: セグメント フォールトと I/O の可能性のあるエラーがコードに多数表示されますが、それらを理解することはできません。print ステートメントから、多くの奇妙で一貫性のない動作を見てきました。これは、おそらく競合状態を示しています。多くの場合、すべてが完璧に機能します。ワーカー デストラクタが呼び出された直後に、メイン接続の deleteLater() の問題を示す I/O エラーが発生することがあります。また、デストラクタで audioOutput を削除しようとすると、何度も機能し、他の試みでデストラクタの途中でランダムにセグメント障害 (または I/O) が発生します。私の問題は、worker cleanup/ connect quit()/deletelater() 呼び出しの 2 つと、毎回独自のイベント ループを作成する必要がある worker の再帰ループに起因する可能性があるため、以前の呼び出しが行われる前に終了信号を発する可能性があると考えています。掃除した?
具体的には、私の質問は次のとおりです。
deleteLater() が I/O の可能性のあるエラーを作成する原因は何ですか?
ワーカークラス内のポインターを削除して、正しい時間(終了)に削除するにはどうすればよいですか?またはQTがこれを処理しますか?
Gui と .h
QByteArray* qbyte;
QThread* thread;
PlayAudio* audioWorker;
MainWindow::startSound()
{
QFile soundFile;
soundFile.setFileName("/home/sounds/sound.wav");
qbyte = new QByteArray(soundFile.readAll());
soundFile.close();
thread= new QThread;
audioWorker= new PlayAudio(qbyte, 5);
audioWorker->moveToThread(thread);
connect(thread, SIGNAL(started()), audioWorker, SLOT(play()));
connect(audioWorker, SIGNAL(finished()), thread, SLOT(quit()));
connect(audioWorker, SIGNAL(finished()), audioWorker,SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(donePlaying()));
}
MainWindow::donePlaying()
{
//do stuff
}
ワーカー クラスと .h
QByteArray qbyte;
int numOfPlays;
int numOfPlaysRun;
bool quit = false;
QBuffer *qbuff;
QAudioFormat format;
QAudioOutput *audioOutput;
PlayAudio::PlayAudio(QByteArray *qbyte_, int num)
{
qbyte=*qbyte_;
numOfPlays=num;
qbuff=new QBuffer();
qbuff->setData(qbyte);
qbuff->open(QIODevice::ReadOnly);
//set format
audioOutput = new QAudioOutput(format,this);
connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),
SLOT(finishedPlaying(QAudio::State)));
}
void PlayAudio::::play()
{
if (!quit)
{
audioOutput->start(qbuff);
QEventLoop loop;
do {
loop.exec();
} while(!quit);
}
}
void PlayAudio::finishedPlaying(QAudio::State state)
{
if (state == QAudio::IdleState)
{
if (numOfPlaysRun< numOfPlays && !quit)
{
numOfPlaysRun++;
play();
}
else
{
//should i ever stop loop myself? or is that done from main?
//quit=true;
emit finished();
}
}
}
PlayAudio:: ~PlayAudio()
{
// still have qbuff and audioOutput to delete. If i do here i sometimes
//get segment faults or IO error.
}
更新しました:
まだ断続的な問題がありますが、次の行をコメントアウトすると、quit=true の設定と組み合わせていくつかの問題を解決できました。
connect(audioWorker, SIGNAL(finished()), audioWorker,SLOT(deleteLater()));
しかし、これはメモリリークを引き起こす可能性がありますか?
更新 2:
ここで独り言を言っていると思い始めていますが、わかったと思います。これは、ワーカが finished() を発行すると、オープン ループを閉じる quit() シグナルからアンワインドする時間が原因で、ワーカが実際に終了する前にスレッドが finished() を返していたため、タイミングの問題であったようです。そのため、閉じたループごとにワーカーからカスタム シグナルを発行し、これをメインで追跡します。期待どおりの結果を受け取ったら、wait() を解放し、スレッドを削除してからワーカーを削除します。これが正しいかどうかはわかりませんが、機能しているようです。私にはハックのように思えますが、IMO ワーカーが終了するまでスレッドは終了してはならず、無意味に思えます。でもまあ。