use Qt Concurrent instead of pthread

This commit is contained in:
Martchus 2016-03-10 22:13:43 +01:00
parent 70b94fa5fa
commit eaea2e2cda
9 changed files with 357 additions and 353 deletions

View File

@ -178,7 +178,8 @@ find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5Script REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(Qt5Network REQUIRED)
# select Qt module providing JavaScript (either Qt Script or Qt Qml)
if(${JS_PROVIDER} STREQUAL "auto")
find_package(Qt5Script)
@ -258,7 +259,7 @@ add_custom_target(translations ALL DEPENDS ${QM_FILES})
# executable and linking
add_executable(${META_PROJECT_NAME} ${GUI_TYPE} ${HEADER_FILES} ${SRC_FILES} ${WIDGETS_HEADER_FILES} ${WIDGETS_SRC_FILES} ${WIDGETS_UI_FILES} ${QM_FILES} ${RES_FILES} ${WINDOWS_ICON_PATH})
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser pthread Qt5::Core Qt5::Widgets ${JS_PROVIDER} ${WEBVIEW_PROVIDER})
target_link_libraries(${META_PROJECT_NAME} c++utilities qtutilities tagparser Qt5::Core Qt5::Widgets Qt5::Concurrent Qt5::Network ${JS_PROVIDER} ${WEBVIEW_PROVIDER})
set_target_properties(${META_PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
)

View File

@ -14,6 +14,7 @@
#include <qtutilities/aboutdialog/aboutdialog.h>
#include <qtutilities/misc/dialogutils.h>
#include <qtutilities/misc/desktoputils.h>
#include <qtutilities/misc/trylocker.h>
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/io/path.h>
@ -30,6 +31,7 @@ using namespace Utility;
using namespace Media;
using namespace Dialogs;
using namespace Widgets;
using namespace ThreadingUtils;
namespace QtGui {
@ -51,7 +53,7 @@ enum LoadingResult : char
/*!
* \brief Shortcut to access file operation mutex of TagEditorWidget.
*/
std::mutex &MainWindow::fileOperationMutex()
QMutex &MainWindow::fileOperationMutex()
{
return m_ui->tagEditorWidget->fileOperationMutex();
}
@ -436,11 +438,8 @@ void MainWindow::showOpenFileDlg()
*/
void MainWindow::saveFileInformation()
{
if(!fileOperationMutex().try_lock()) {
m_ui->statusBar->showMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
return;
}
lock_guard<mutex> guard(fileOperationMutex(), adopt_lock);
TryLocker<> locker(fileOperationMutex());
if(locker) {
if(fileInfo().isOpen() && m_ui->tagEditorWidget->fileInfoHtml().size()) {
const QString path = QFileDialog::getSaveFileName(this, windowTitle());
if(!path.isEmpty()) {
@ -459,6 +458,9 @@ void MainWindow::saveFileInformation()
} else {
QMessageBox::information(this, QApplication::applicationName(), tr("No file information available."));
}
} else {
m_ui->statusBar->showMessage(tr("Unable to save file information because the current process hasn't been finished yet."));
}
}
/*!

View File

@ -10,10 +10,9 @@
#include <QMainWindow>
#include <QByteArray>
#include <mutex>
QT_FORWARD_DECLARE_CLASS(QFileSystemModel)
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
QT_FORWARD_DECLARE_CLASS(QMutex)
namespace Media {
DECLARE_ENUM(TagType, unsigned int)
@ -73,7 +72,7 @@ private slots:
void showDbQueryWidget();
private:
std::mutex &fileOperationMutex();
QMutex &fileOperationMutex();
Media::MediaFileInfo &fileInfo();
// UI

View File

@ -20,8 +20,6 @@
#include <QClipboard>
#include <QTextStream>
#include <thread>
using namespace Dialogs;
using namespace RenamingUtility;

View File

@ -21,6 +21,8 @@
#include <tagparser/matroska/matroskatag.h>
#include <qtutilities/misc/dialogutils.h>
#include <qtutilities/misc/trylocker.h>
#include <qtutilities/misc/adoptlocker.h>
#include <qtutilities/widgets/clearlineedit.h>
#include <c++utilities/conversion/stringconversion.h>
@ -35,6 +37,8 @@
#include <QFileSystemWatcher>
#include <QMenu>
#include <QCheckBox>
#include <QtConcurrent>
#include <QFutureWatcher>
#if defined(TAGEDITOR_NO_WEBVIEW)
# error "not supported (yet)."
#elif defined(TAGEDITOR_USE_WEBENGINE)
@ -43,7 +47,6 @@
# include <QWebView>
#endif
#include <thread>
#include <functional>
#include <algorithm>
@ -51,6 +54,7 @@ using namespace std;
using namespace Utility;
using namespace Dialogs;
using namespace Widgets;
using namespace ThreadingUtils;
using namespace Media;
namespace QtGui {
@ -602,11 +606,8 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
if(!forceRefresh && sameFile) {
return true;
}
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage(tr("Unable to load the selected file \"%1\" because the current process hasn't finished yet.").arg(path));
return false;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(fileOperationMutex());
if(locker) {
// clear previous results and status
m_tags.clear();
m_fileInfo.clearParsingResults();
@ -640,10 +641,10 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
m_fileInfo.setForceFullParse(Settings::forceFullParse());
m_fileInfo.parseEverything();
result = ParsingSuccessful;
} catch(Failure &) {
} catch(const Failure &) {
// the file has been opened; parsing notifications will be shown in the info box
result = FatalParsingError;
} catch(ios_base::failure &) {
} catch(const ios_base::failure &) {
// the file could not be opened because an IO error occured
m_fileInfo.close(); // ensure file is closed
result = IoError;
@ -653,10 +654,8 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
// showFile() will unlock the mutex!
};
m_fileInfo.unregisterAllCallbacks();
//m_fileInfo.registerCallback(showProgress); can't show progress yet
// use another thread to perform the operation
std::thread thr(startThread);
thr.detach();
// perform the operation concurrently
QtConcurrent::run(startThread);
// inform user
static const QString statusMsg(tr("The file is beeing parsed ..."));
m_ui->parsingNotificationWidget->setNotificationType(NotificationType::Progress);
@ -664,6 +663,10 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
m_ui->parsingNotificationWidget->setVisible(true); // ensure widget is visible!
emit statusMessage(statusMsg);
return true;
} else {
emit statusMessage(tr("Unable to load the selected file \"%1\" because the current process hasn't finished yet.").arg(path));
}
return false;
}
/*!
@ -671,16 +674,17 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
*/
bool TagEditorWidget::reparseFile()
{
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage(tr("Unable to reload the file because the current process hasn't finished yet."));
return false;
}
{
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
if(!m_fileInfo.isOpen() || m_currentPath.isEmpty()) {
QMessageBox::warning(this, windowTitle(), tr("Currently is not file opened."));
return false;
}
} else {
emit statusMessage(tr("Unable to reload the file because the current process hasn't finished yet."));
return false;
}
}
return startParsing(m_currentPath, true);
}
@ -694,7 +698,7 @@ bool TagEditorWidget::reparseFile()
*/
void TagEditorWidget::showFile(char result)
{
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
AdoptLocker<> locker(m_fileOperationMutex);
if(result == IoError) {
// update status
updateFileStatusStatus();
@ -787,13 +791,8 @@ void TagEditorWidget::saveAndShowNextFile()
bool TagEditorWidget::applyEntriesAndSaveChangings()
{
{
if(!m_fileOperationMutex.try_lock()) {
static const QString statusMsg(tr("Unable to apply the entered tags to the file because the current process hasn't finished yet."));
m_ui->makingNotificationWidget->setText(statusMsg);
emit statusMessage(statusMsg);
return false;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
m_ui->makingNotificationWidget->setNotificationType(NotificationType::Information);
m_ui->makingNotificationWidget->setNotificationSubject(NotificationSubject::Saving);
m_ui->makingNotificationWidget->setHidden(false);
@ -816,11 +815,17 @@ bool TagEditorWidget::applyEntriesAndSaveChangings()
m_ui->makingNotificationWidget->setText(statusMsg);
emit statusMessage(statusMsg);
} else {
QString statusMsg = tr("No file has been opened.");
QString statusMsg(tr("No file has been opened."));
m_ui->makingNotificationWidget->setText(statusMsg);
QMessageBox::warning(this, QApplication::applicationName(), statusMsg);
return false;
}
} else {
static const QString statusMsg(tr("Unable to apply the entered tags to the file because the current process hasn't finished yet."));
m_ui->makingNotificationWidget->setText(statusMsg);
emit statusMessage(statusMsg);
return false;
}
}
return startSaving();
}
@ -832,13 +837,8 @@ bool TagEditorWidget::applyEntriesAndSaveChangings()
bool TagEditorWidget::deleteAllTagsAndSave()
{
{
if(!m_fileOperationMutex.try_lock()) {
static const QString statusMsg(tr("Unable to delete all tags from the file because the current process hasn't been finished yet."));
m_ui->makingNotificationWidget->setText(statusMsg);
emit statusMessage(statusMsg);
return false;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
if(Settings::askBeforeDeleting()) {
QMessageBox msgBox(this);
msgBox.setText(tr("Do you really want to delete all tags from the file?"));
@ -881,6 +881,12 @@ bool TagEditorWidget::deleteAllTagsAndSave()
m_ui->makingNotificationWidget->setText(tr("No file has been opened, so no tags can be deleted."));
return false;
}
} else {
static const QString statusMsg(tr("Unable to delete all tags from the file because the current process hasn't been finished yet."));
m_ui->makingNotificationWidget->setText(statusMsg);
emit statusMessage(statusMsg);
return false;
}
}
return startSaving();
}
@ -896,13 +902,8 @@ bool TagEditorWidget::deleteAllTagsAndSave()
*/
bool TagEditorWidget::startSaving()
{
if(!m_fileOperationMutex.try_lock()) {
static const QString errorMsg(tr("Unable to start saving process because there an other process hasn't finished yet."));
emit statusMessage(errorMsg);
QMessageBox::warning(this, QApplication::applicationName(), errorMsg);
return false;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
// tags might get invalidated
m_tags.clear();
foreachTagEdit([] (TagEdit *edit) { edit->setTag(nullptr, false); });
@ -948,9 +949,14 @@ bool TagEditorWidget::startSaving()
m_fileInfo.unregisterAllCallbacks();
m_fileInfo.registerCallback(showProgress);
// use another thread to perform the operation
std::thread thr(startThread);
thr.detach();
QtConcurrent::run(startThread);
return true;
} else {
static const QString errorMsg(tr("Unable to start saving process because there an other process hasn't finished yet."));
emit statusMessage(errorMsg);
QMessageBox::warning(this, QApplication::applicationName(), errorMsg);
return false;
}
}
/*!
@ -1055,11 +1061,8 @@ void TagEditorWidget::fileChangedOnDisk(const QString &path)
*/
void TagEditorWidget::closeFile()
{
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage("Unable to close the file because the current process hasn't been finished yet.");
return;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
// close file
m_fileInfo.close();
// remove current path from file watcher
@ -1067,6 +1070,9 @@ void TagEditorWidget::closeFile()
// update ui
emit statusMessage("The file has been closed.");
updateFileStatusStatus();
} else {
emit statusMessage("Unable to close the file because the current process hasn't been finished yet.");
}
}
/*!
@ -1119,11 +1125,8 @@ void TagEditorWidget::applySettingsFromDialog()
*/
void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)> &createTag)
{
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage("Unable to add a tag because the current process hasn't been finished yet.");
return;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
if(!m_fileInfo.isOpen()) {
emit statusMessage("Unable to add a tag because no file is opened.");
return;
@ -1139,10 +1142,12 @@ void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)
} else {
QMessageBox::warning(this, windowTitle(), tr("A tag (with the selected target) already exists."));
}
} else {
QMessageBox::warning(this, windowTitle(), tr("The tag can not be created."));
}
} else {
emit statusMessage("Unable to add a tag because the current process hasn't been finished yet.");
}
}
/*!
@ -1153,11 +1158,8 @@ void TagEditorWidget::addTag(const function<Media::Tag *(Media::MediaFileInfo &)
void TagEditorWidget::removeTag(Tag *tag)
{
if(tag) {
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage(tr("Unable to remove the tag because the current process hasn't been finished yet."));
return;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
if(!m_fileInfo.isOpen()) {
emit statusMessage(tr("Unable to remove the tag because no file is opened."));
return;
@ -1200,6 +1202,9 @@ void TagEditorWidget::removeTag(Tag *tag)
updateTagManagementMenu();
updateFileStatusStatus();
}
} else {
emit statusMessage(tr("Unable to remove the tag because the current process hasn't been finished yet."));
}
}
}
@ -1211,11 +1216,8 @@ void TagEditorWidget::removeTag(Tag *tag)
void TagEditorWidget::changeTarget(Tag *tag)
{
if(tag) {
if(!m_fileOperationMutex.try_lock()) {
emit statusMessage(tr("Unable to change the target because the current process hasn't been finished yet."));
return;
}
lock_guard<mutex> guard(m_fileOperationMutex, adopt_lock);
TryLocker<> locker(m_fileOperationMutex);
if(locker) {
if(!m_fileInfo.isOpen()) {
emit statusMessage(tr("Unable to change the target because no file is opened."));
return;
@ -1233,6 +1235,9 @@ void TagEditorWidget::changeTarget(Tag *tag)
QMessageBox::warning(this, windowTitle(), tr("Can not change the target of the selected tag because the tag does not support targets."));
}
}
} else {
emit statusMessage(tr("Unable to change the target because the current process hasn't been finished yet."));
}
}
}

View File

@ -7,8 +7,8 @@
#include <QWidget>
#include <QByteArray>
#include <QMutex>
#include <mutex>
#include <functional>
#if defined(TAGEDITOR_NO_WEBVIEW)
@ -50,7 +50,7 @@ public:
virtual ~TagEditorWidget();
public:
std::mutex &fileOperationMutex();
QMutex &fileOperationMutex();
const QString &currentPath() const;
Media::MediaFileInfo &fileInfo();
bool isTagEditShown() const;
@ -149,13 +149,13 @@ private:
bool m_makingResultsAvailable;
Media::NotificationList m_originalNotifications;
bool m_abortClicked;
std::mutex m_fileOperationMutex;
QMutex m_fileOperationMutex;
};
/*!
* \brief Returns the mutex which is internally used for thread-synchronization.
*/
inline std::mutex &TagEditorWidget::fileOperationMutex()
inline QMutex &TagEditorWidget::fileOperationMutex()
{
return m_fileOperationMutex;
}

View File

@ -5,12 +5,14 @@
#include <c++utilities/misc/memory.h>
#include <qtutilities/misc/trylocker.h>
#include <QDir>
#include <QStringBuilder>
#include <thread>
#include <QtConcurrent>
using namespace std;
using namespace ThreadingUtils;
namespace RenamingUtility {
@ -55,26 +57,25 @@ bool RemamingEngine::setProgram(const QString &program)
bool RemamingEngine::generatePreview(const QDir &rootDirectory, bool includeSubdirs)
{
if(!m_mutex.try_lock()) {
return false;
}
lock_guard<mutex> guard(m_mutex, adopt_lock);
TryLocker<> locker(m_mutex);
if(locker) {
setRootItem();
m_includeSubdirs = includeSubdirs;
m_dir = rootDirectory;
auto startFunc = [this] () {
QtConcurrent::run([this] () {
{
lock_guard<mutex> guard(m_mutex);
QMutexLocker locker(&m_mutex);
m_aborted.store(false);
m_itemsProcessed = 0;
m_errorsOccured = 0;
m_newlyGeneratedRootItem = generatePreview(m_dir);
}
emit previewGenerated();
};
std::thread thread(startFunc);
thread.detach();
});
return true;
} else {
return false;
}
}
bool RemamingEngine::applyChangings()
@ -82,28 +83,27 @@ bool RemamingEngine::applyChangings()
if(!m_rootItem) {
return false;
}
if(!m_mutex.try_lock()) {
return false;
}
lock_guard<mutex> guard(m_mutex, adopt_lock);
auto startFunc = [this] () {
TryLocker<> locker(m_mutex);
if(locker) {
QtConcurrent::run([this] () {
{
lock_guard<mutex> guard(m_mutex);
QMutexLocker locker(&m_mutex);
m_aborted.store(false);
m_itemsProcessed = 0;
m_errorsOccured = 0;
applyChangings(m_rootItem.get());
}
emit changingsApplied();
};
std::thread thread(startFunc);
thread.detach();
});
return true;
} else {
return false;
}
}
bool RemamingEngine::isBusy()
{
if(m_mutex.try_lock()) {
if(m_mutex.tryLock()) {
m_mutex.unlock();
return false;
} else {
@ -113,7 +113,7 @@ bool RemamingEngine::isBusy()
void RemamingEngine::abort()
{
m_aborted.store(true);
m_aborted.store(1);
}
bool RemamingEngine::isAborted()
@ -123,8 +123,8 @@ bool RemamingEngine::isAborted()
bool RemamingEngine::clearPreview()
{
if(m_mutex.try_lock()) {
lock_guard<mutex> guard(m_mutex, adopt_lock);
TryLocker<> locker(m_mutex);
if(locker) {
updateModel(nullptr);
m_rootItem.reset();
return true;

View File

@ -7,7 +7,8 @@
#include <QObject>
#include <QList>
#include <QDir>
#include <QMutex>
#include <QAtomicInteger>
#if TAGEDITOR_USE_JSENGINE
# include <QJSEngine>
# include <QJSValue>
@ -17,8 +18,6 @@
#endif
#include <memory>
#include <mutex>
#include <atomic>
QT_FORWARD_DECLARE_CLASS(QFileInfo)
@ -79,11 +78,11 @@ private:
std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem;
int m_itemsProcessed;
int m_errorsOccured;
std::atomic<bool> m_aborted;
QAtomicInteger<unsigned char> m_aborted;
TAGEDITOR_JS_VALUE m_program;
QDir m_dir;
bool m_includeSubdirs;
std::mutex m_mutex;
QMutex m_mutex;
FileSystemItemModel *m_model;
FilteredFileSystemItemModel *m_currentModel;
FilteredFileSystemItemModel *m_previewModel;

View File

@ -15,7 +15,7 @@ VERSION = 1.4.0
# basic configuration: application
TEMPLATE = app
QT += core gui widgets
QT += core gui widgets concurrent network
# use webkitwidgets if available; otherwise use webenginewidgets
!forcewebengine:qtHaveModule(webkitwidgets) {
QT += webkitwidgets