From 167d3db82e60173075e18d5c8f6df2321e3eca4b Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Mon, 9 Aug 2021 04:26:27 +0300 Subject: [PATCH] Separate decoding and analyzing pools. Fix crash on deleting analyzed object. --- arfariusapplication.cpp | 12 +++++++++++- arfariusapplication.h | 10 ++++++++++ player.cpp | 37 ++++++++++++++++++++++--------------- playlistitem.cpp | 13 +++++++++++-- playlistitem.h | 4 ++++ playlistmodel.cpp | 8 +++++--- 6 files changed, 63 insertions(+), 21 deletions(-) diff --git a/arfariusapplication.cpp b/arfariusapplication.cpp index 8a640f7..01d398d 100644 --- a/arfariusapplication.cpp +++ b/arfariusapplication.cpp @@ -2,7 +2,9 @@ #include ArfariusApplication::ArfariusApplication(int & argc, char ** argv) : - QApplication(argc, argv) + QApplication(argc, argv), + decoder_thread_pool(this), + analyze_thread_pool(this) { } @@ -16,3 +18,11 @@ bool ArfariusApplication::event(QEvent *event) return QApplication::event(event); } } + +QThreadPool* ArfariusApplication::getDecoderThreadPool() { + return &decoder_thread_pool; +} + +QThreadPool* ArfariusApplication::getAnalyzeThreadPool() { + return &analyze_thread_pool; +} diff --git a/arfariusapplication.h b/arfariusapplication.h index 1ddd137..82c0d8d 100644 --- a/arfariusapplication.h +++ b/arfariusapplication.h @@ -2,15 +2,25 @@ #define WMPAPPLICATION_H #include +#include #include +#define arfariusApp (static_cast(QCoreApplication::instance())) + class ArfariusApplication : public QApplication { Q_OBJECT + + QThreadPool decoder_thread_pool; + QThreadPool analyze_thread_pool; + public: explicit ArfariusApplication(int &argc, char **argv); bool event(QEvent *); + QThreadPool *getDecoderThreadPool(); + QThreadPool *getAnalyzeThreadPool(); + signals: void fileDropped(QUrl); diff --git a/player.cpp b/player.cpp index ab797e9..f25afef 100644 --- a/player.cpp +++ b/player.cpp @@ -1,5 +1,6 @@ #include "player.h" +#include "arfariusapplication.h" #include "playlistmodel.h" #include "playlistitem.h" @@ -128,14 +129,17 @@ void Player::ejectFile() if (file) { file->cancelDecoding(); - eject_future = QtConcurrent::run([this](){ - av_sample_t *buffer = new av_sample_t[4096]; - while (state != Player::PLAY && file) { - qDebug() << this << "ejectFile(): pumping samples"; - pull(buffer, 4096); + eject_future = QtConcurrent::run( + arfariusApp->getDecoderThreadPool(), + [this](){ + av_sample_t *buffer = new av_sample_t[4096]; + while (state != Player::PLAY && file) { + qDebug() << this << "ejectFile(): pumping samples"; + pull(buffer, 4096); + } + delete [] buffer ; } - delete [] buffer ; - }); + ); file_future.waitForFinished(); eject_future.waitForFinished(); } @@ -161,15 +165,18 @@ void Player::updateItem(PlayListItem *item) file->setSamplerate(_sample_rate); file->setChannels(_channels); file->connectOutput(this); - file_future = QtConcurrent::run([this](){ - file->decode(); - delete file; file = 0; - if (quiet) { - quiet = false; - } else { - emit trackEnded(); + file_future = QtConcurrent::run( + arfariusApp->getDecoderThreadPool(), + [this](){ + file->decode(); + delete file; file = 0; + if (quiet) { + quiet = false; + } else { + emit trackEnded(); + } } - }); + ); if (state != Player::PLAY) { startStream(); diff --git a/playlistitem.cpp b/playlistitem.cpp index 96c61cd..e04c918 100644 --- a/playlistitem.cpp +++ b/playlistitem.cpp @@ -4,6 +4,7 @@ #include #include +#include "arfariusapplication.h" #include "avexception.h" #include "avsplitter.h" #include "avhistogram.h" @@ -59,7 +60,7 @@ TagLib::String toString(QString str) { */ PlayListItem::PlayListItem(QUrl s) : - QObject(), source(s), artist(), title(), album(), duration(-1) + QObject(), source(s), artist(), title(), album(), duration(-1), busy(false) { } @@ -68,6 +69,10 @@ PlayListItem::~PlayListItem() { } +bool PlayListItem::isBusy() { + return busy; +} + bool PlayListItem::isValid() { try { @@ -235,7 +240,11 @@ bool PlayListItem::hasHistogram() void PlayListItem::ensureHistogram() { if (!hasHistogram()) { - QtConcurrent::run([&]{ auto hack = this; analyze(); hack = nullptr; }); + busy = true; + QtConcurrent::run( + arfariusApp->getAnalyzeThreadPool(), + [this]{ analyze(); busy = false; } + ); } } diff --git a/playlistitem.h b/playlistitem.h index 16f100d..f76a6d9 100644 --- a/playlistitem.h +++ b/playlistitem.h @@ -2,6 +2,7 @@ #define PLAYLISTITEM_H #include +#include #include class AVFile; @@ -13,6 +14,7 @@ class PlayListItem : public QObject PlayListItem(QUrl s); virtual ~PlayListItem(); + bool isBusy(); bool isValid(); bool isLocalFile(); @@ -45,6 +47,8 @@ class PlayListItem : public QObject QString album; int duration; + bool busy; + QString getArtist(); QString getTitle(); QString getAlbum(); diff --git a/playlistmodel.cpp b/playlistmodel.cpp index d0a5633..3153e71 100644 --- a/playlistmodel.cpp +++ b/playlistmodel.cpp @@ -1,5 +1,6 @@ #include "playlistmodel.h" #include "playlistitem.h" +#include "arfariusapplication.h" #include #include @@ -93,9 +94,10 @@ bool PlayListModel::removeRows(int row, int count, const QModelIndex &parent) current_item = items[current]; } - for (int i = 0; i < count; ++i) { - items[row]->deleteLater(); - items.removeAt(row); + for (int i = row; i < row+count; i++) { + while(items[i]->isBusy()) arfariusApp->processEvents(QEventLoop::AllEvents, 10); + items[i]->deleteLater(); + items.removeAt(i); } if (current_item) {