Moved lock-guarding abilities to separated template class.

Changed application/mainwindow to use it. Most likelly mainwindow may be
upgraded more, since lock can hold and manage memory for complex object
like QFile, also it can have stored deallocator for the object
(lambdas), so this is effectively should simple code, when you have
allocation and freening resources declared on the same screen.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2015-09-14 14:53:49 +03:00
parent 1e806ccc08
commit cf0d1981ca
10 changed files with 268 additions and 200 deletions

View File

@ -37,6 +37,7 @@
#include "../ifc/xml/vvitconverter.h" #include "../ifc/xml/vvitconverter.h"
#include "../ifc/xml/vvstconverter.h" #include "../ifc/xml/vvstconverter.h"
#include "../ifc/xml/vpatternconverter.h" #include "../ifc/xml/vpatternconverter.h"
#include "../vmisc/vlockguard.h"
#include "vlitepattern.h" #include "vlitepattern.h"
#include "../qmuparser/qmudef.h" #include "../qmuparser/qmudef.h"
#include "../vtools/dialogs/support/dialogeditwrongformula.h" #include "../vtools/dialogs/support/dialogeditwrongformula.h"
@ -48,9 +49,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QComboBox> #include <QComboBox>
#include <QProcess> #include <QProcess>
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
# include <QLockFile>
#endif
#define DIALOG_MAX_FORMULA_HEIGHT 64 #define DIALOG_MAX_FORMULA_HEIGHT 64
@ -98,10 +96,6 @@ TMainWindow::~TMainWindow()
delete m; delete m;
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
delete lock; // Unlock pattern file
#endif
delete ui; delete ui;
} }
@ -182,18 +176,13 @@ void TMainWindow::LoadFile(const QString &path)
} }
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) VlpCreateLock(lock, QFileInfo(path).fileName()+".lock");
lock = new QLockFile(QFileInfo(path).fileName()+".lock");
lock->setStaleLockTime(0); if (lock->GetLockError() == QLockFile::LockFailedError)
if (not MApplication::TryLock(lock))
{ {
if (lock->error() == QLockFile::LockFailedError) qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData());
{ return;
qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData());
return;
}
} }
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
try try
{ {
@ -839,18 +828,13 @@ void TMainWindow::ImportFromPattern()
return; return;
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) VLockGuard<char> tmp(QFileInfo(mPath).fileName()+".lock");
QLockFile *lock = new QLockFile(QFileInfo(mPath).fileName()+".lock");
lock->setStaleLockTime(0); if (tmp.GetLockError() == QLockFile::LockFailedError)
if (not MApplication::TryLock(lock))
{ {
if (lock->error() == QLockFile::LockFailedError) qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData());
{ return;
qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData());
return;
}
} }
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
qt_ntfs_permission_lookup++; // turn checking on qt_ntfs_permission_lookup++; // turn checking on
@ -878,8 +862,6 @@ void TMainWindow::ImportFromPattern()
qt_ntfs_permission_lookup--; // turn it off again qt_ntfs_permission_lookup--; // turn it off again
#endif /*Q_OS_WIN32*/ #endif /*Q_OS_WIN32*/
delete lock; // release a pattern file
measurements = FilterMeasurements(measurements, m->ListAll()); measurements = FilterMeasurements(measurements, m->ListAll());
qint32 currentRow; qint32 currentRow;

View File

@ -33,6 +33,7 @@
#include <QTableWidget> #include <QTableWidget>
#include "../vmisc/def.h" #include "../vmisc/def.h"
#include "../vmisc/vlockguard.h"
#include "../vformat/vmeasurements.h" #include "../vformat/vmeasurements.h"
namespace Ui namespace Ui
@ -43,9 +44,6 @@ namespace Ui
class QComboBox; class QComboBox;
class QTableWidgetItem; class QTableWidgetItem;
class QLabel; class QLabel;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
class QLockFile;
#endif
class TMainWindow : public QMainWindow class TMainWindow : public QMainWindow
{ {
@ -133,10 +131,7 @@ private:
QComboBox *gradationSizes; QComboBox *gradationSizes;
QComboBox *comboBoxUnits; QComboBox *comboBoxUnits;
int formulaBaseHeight; int formulaBaseHeight;
VLockGuardPtr<char> lock;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
QLockFile *lock;
#endif
void SetupMenu(); void SetupMenu();
void InitWindow(); void InitWindow();

View File

@ -53,6 +53,8 @@
Q_LOGGING_CATEGORY(vApp, "v.application") Q_LOGGING_CATEGORY(vApp, "v.application")
constexpr auto DAYS_TO_KEEP_LOGS = 3;
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
@ -170,12 +172,8 @@ const QString VApplication::GistFileName = QStringLiteral("gist.json");
VApplication::VApplication(int &argc, char **argv) VApplication::VApplication(int &argc, char **argv)
: VAbstractApplication(argc, argv), : VAbstractApplication(argc, argv),
trVars(nullptr), autoSaveTimer(nullptr), trVars(nullptr), autoSaveTimer(nullptr),
log(nullptr), lockLog(),
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
out(nullptr), logLock(nullptr)
#else
out(nullptr) out(nullptr)
#endif
{ {
VCommandLine::Reset(); // making sure will create new instance...just in case we will ever do 2 objects of VApplication VCommandLine::Reset(); // making sure will create new instance...just in case we will ever do 2 objects of VApplication
VCommandLine::Get(*this); VCommandLine::Get(*this);
@ -187,16 +185,6 @@ VApplication::~VApplication()
{ {
qCDebug(vApp, "Application closing."); qCDebug(vApp, "Application closing.");
qInstallMessageHandler(0); // Resore the message handler qInstallMessageHandler(0); // Resore the message handler
delete out;
if (log != nullptr)
{
log->close();
delete log;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
delete logLock;
#endif
}
delete trVars; delete trVars;
VCommandLine::Reset(); VCommandLine::Reset();
} }
@ -418,32 +406,25 @@ void VApplication::CreateLogDir() const
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VApplication::BeginLogging() void VApplication::BeginLogging()
{ {
log = new QFile(LogPath()); VlpCreateLock(lockLog, LogPath()+".lock", [this](){return new QFile(LogPath());});
if (log->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
out = new QTextStream(log);
qInstallMessageHandler(noisyFailureMsgHandler);
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) if (lockLog->IsLocked())
logLock = new QLockFile(LogPath()+".lock"); {
logLock->setStaleLockTime(0); if (lockLog->GetProtected()->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
if (TryLock(logLock))
{ {
out.reset(new QTextStream(lockLog->GetProtected().get()));
qInstallMessageHandler(noisyFailureMsgHandler);
qCDebug(vApp, "Log file %s was locked.", LogPath().toUtf8().constData()); qCDebug(vApp, "Log file %s was locked.", LogPath().toUtf8().constData());
} }
else else
{ {
qCDebug(vApp, "Failed to lock %s", LogPath().toUtf8().constData()); qCDebug(vApp, "Error opening log file \'%s\'. All debug output redirected to console.",
qCDebug(vApp, "Error type: %d", logLock->error()); LogPath().toUtf8().constData());
} }
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
} }
else else
{ {
delete log; qCDebug(vApp, "Failed to lock %s", LogPath().toUtf8().constData());
log = nullptr;
qCDebug(vApp, "Error opening log file \'%s\'. All debug output redirected to console.",
LogPath().toUtf8().constData());
} }
} }
@ -459,45 +440,29 @@ void VApplication::ClearOldLogs() const
if (allFiles.isEmpty() == false) if (allFiles.isEmpty() == false)
{ {
qCDebug(vApp, "Clearing old logs"); qCDebug(vApp, "Clearing old logs");
for (int i = 0; i < allFiles.size(); ++i) for (int i = 0, sz = allFiles.size(); i < sz; ++i)
{ {
QFileInfo info(allFiles.at(i)); auto fn = allFiles.at(i);
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) QFileInfo info(fn);
QLockFile *lock = new QLockFile(info.absoluteFilePath() + ".lock"); if (info.created().daysTo(QDateTime::currentDateTime()) >= DAYS_TO_KEEP_LOGS)
if (TryLock(lock))
{ {
qCDebug(vApp, "Locked file %s", info.absoluteFilePath().toUtf8().constData()); VLockGuard<QFile> tmp(info.absoluteFilePath() + ".lock", [&fn](){return new QFile(fn);});
QFile oldLog(allFiles.at(i)); if (tmp.GetProtected() != nullptr)
if (oldLog.remove())
{ {
qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData()); if (tmp.GetProtected()->remove())
{
qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData());
}
else
{
qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData());
}
} }
else else
{ {
qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData()); qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData());
} }
} }
else
{
qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData());
}
delete lock;
lock = nullptr;
#else
if (info.created().daysTo(QDateTime::currentDateTime()) >= 3)
{
QFile oldLog(allFiles.at(i));
if (oldLog.remove())
{
qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData());
}
else
{
qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData());
}
}
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
} }
} }
else else
@ -614,7 +579,7 @@ void VApplication::StartLogging()
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
QTextStream *VApplication::LogFile() QTextStream *VApplication::LogFile()
{ {
return out; return out.get();
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -707,27 +672,28 @@ void VApplication::GatherLogs() const
const QStringList allFiles = logsDir.entryList(QDir::NoDotAndDotDot | QDir::Files); const QStringList allFiles = logsDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
if (allFiles.isEmpty() == false) if (allFiles.isEmpty() == false)
{ {
for (int i = 0; i < allFiles.size(); ++i) for (int i = 0, sz = allFiles.size(); i < sz; ++i)
{ {
QFileInfo info(allFiles.at(i)); auto fn = allFiles.at(i);
QFileInfo info(fn);
if (info.fileName() == "valentina.log") if (info.fileName() == "valentina.log")
{ {
continue; continue;
} }
QLockFile *logLock = new QLockFile(info.absoluteFilePath()+".lock");
logLock->setStaleLockTime(0); VLockGuard<QFile> tmp(info.absoluteFilePath() + ".lock", [&fn](){return new QFile(fn);});
if (TryLock(logLock))
if (tmp.IsLocked())
{ {
*out <<"--------------------------" << endl; *out <<"--------------------------" << endl;
QFile logFile(info.absoluteFilePath()); if (tmp.GetProtected()->open(QIODevice::ReadOnly | QIODevice::Text))
if (logFile.open(QIODevice::ReadOnly | QIODevice::Text))
{ {
QTextStream in(&logFile); QTextStream in(&tmp.GetProtected());
while (!in.atEnd()) while (!in.atEnd())
{ {
*out << in.readLine() << endl; *out << in.readLine() << endl;
} }
logFile.close(); tmp.GetProtected()->close();
} }
else else
{ {
@ -736,9 +702,8 @@ void VApplication::GatherLogs() const
} }
else else
{ {
*out << "Could not lock" << info.absoluteFilePath() << "."; qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData());
} }
delete logLock;
} }
} }
else else

View File

@ -36,7 +36,6 @@
#include "vsettings.h" #include "vsettings.h"
#include "vcmdexport.h" #include "vcmdexport.h"
class VApplication;// use in define class VApplication;// use in define
class VMainGraphicsView; class VMainGraphicsView;
class VPattern; class VPattern;
@ -95,11 +94,9 @@ private:
VTranslateVars *trVars; VTranslateVars *trVars;
QTimer *autoSaveTimer; QTimer *autoSaveTimer;
QFile *log; VLockGuardPtr<QFile> lockLog;
QTextStream *out; std::shared_ptr<QTextStream> out;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
QLockFile *logLock;
#endif
void InitLineWidth(); void InitLineWidth();
#if defined(Q_OS_WIN) && defined(Q_CC_GNU) #if defined(Q_OS_WIN) && defined(Q_CC_GNU)

View File

@ -62,9 +62,6 @@
#include <QtGlobal> #include <QtGlobal>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QDesktopServices> #include <QDesktopServices>
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
# include <QLockFile>
#endif
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@ -1960,13 +1957,8 @@ void MainWindow::OnlineHelp()
void MainWindow::Clear() void MainWindow::Clear()
{ {
qCDebug(vMainWindow, "Reseting main window."); qCDebug(vMainWindow, "Reseting main window.");
lock.reset();
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
delete lock; // Unlock pattern file
lock = nullptr;
qCDebug(vMainWindow, "Unlocked pattern file."); qCDebug(vMainWindow, "Unlocked pattern file.");
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
ui->actionDetails->setChecked(true); ui->actionDetails->setChecked(true);
ui->actionDraw->setChecked(true); ui->actionDraw->setChecked(true);
ui->actionLayout->setEnabled(true); ui->actionLayout->setEnabled(true);
@ -3034,9 +3026,6 @@ MainWindow::~MainWindow()
CancelTool(); CancelTool();
CleanLayout(); CleanLayout();
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
delete lock; // Unlock pattern file
#endif
delete doc; delete doc;
delete sceneDetails; delete sceneDetails;
delete sceneDraw; delete sceneDraw;
@ -3065,26 +3054,24 @@ bool MainWindow::LoadPattern(const QString &fileName, const QString& customMeasu
return false; return false;
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
qCDebug(vMainWindow, "Loking file"); qCDebug(vMainWindow, "Loking file");
lock = new QLockFile(fileName+".lock"); VlpCreateLock(lock, fileName+".lock");
lock->setStaleLockTime(0);
if (VApplication::TryLock(lock)) if (lock->IsLocked())
{ {
qCDebug(vMainWindow, "Pattern file %s was locked.", fileName.toUtf8().constData()); qCDebug(vMainWindow, "Pattern file %s was locked.", fileName.toUtf8().constData());
} }
else else
{ {
qCDebug(vMainWindow, "Failed to lock %s", fileName.toUtf8().constData()); qCDebug(vMainWindow, "Failed to lock %s", fileName.toUtf8().constData());
qCDebug(vMainWindow, "Error type: %d", lock->error()); qCDebug(vMainWindow, "Error type: %d", lock->GetLockError());
if (lock->error() == QLockFile::LockFailedError) if (lock->GetLockError() == QLockFile::LockFailedError)
{ {
qCCritical(vMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); qCCritical(vMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData());
Clear(); Clear();
return false; return false;
} }
} }
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
// On this stage scene empty. Fit scene size to view size // On this stage scene empty. Fit scene size to view size
VMainGraphicsView::NewSceneRect(sceneDraw, ui->view); VMainGraphicsView::NewSceneRect(sceneDraw, ui->view);
@ -3187,14 +3174,11 @@ QStringList MainWindow::GetUnlokedRestoreFileList() const
for (int i = 0; i < files.size(); ++i) for (int i = 0; i < files.size(); ++i)
{ {
// Seeking file that realy need reopen // Seeking file that realy need reopen
QLockFile *lock = new QLockFile(files.at(i)+".lock"); VLockGuard<char> tmp(files.at(i)+".lock");
lock->setStaleLockTime(0); if (tmp.IsLocked())
if (VApplication::TryLock(lock))
{ {
restoreFiles.append(files.at(i)); restoreFiles.append(files.at(i));
} }
delete lock;
lock = nullptr;
} }
// Clearing list after filtering // Clearing list after filtering
@ -3204,7 +3188,6 @@ QStringList MainWindow::GetUnlokedRestoreFileList() const
} }
qApp->ValentinaSettings()->SetRestoreFileList(files); qApp->ValentinaSettings()->SetRestoreFileList(files);
} }
return restoreFiles; return restoreFiles;
#else #else

View File

@ -37,7 +37,7 @@
#include "tools/vtooluniondetails.h" #include "tools/vtooluniondetails.h"
#include "tools/drawTools/drawtools.h" #include "tools/drawTools/drawtools.h"
#include "core/vcmdexport.h" #include "core/vcmdexport.h"
#include <QLockFile> #include "../vmisc/vlockguard.h"
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
@ -47,9 +47,6 @@ namespace Ui
} }
class VToolOptionsPropertyBrowser; class VToolOptionsPropertyBrowser;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
class QLockFile;
#endif
/** /**
* @brief The MainWindow class main windows. * @brief The MainWindow class main windows.
@ -230,9 +227,7 @@ private:
QComboBox *gradationHeights; QComboBox *gradationHeights;
QComboBox *gradationSizes; QComboBox *gradationSizes;
VToolOptionsPropertyBrowser *toolOptions; VToolOptionsPropertyBrowser *toolOptions;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) VLockGuardPtr<char> lock;
QLockFile *lock;
#endif
void ToolBarOption(); void ToolBarOption();
void ToolBarStages(); void ToolBarStages();

View File

@ -29,10 +29,6 @@
#include "vabstractapplication.h" #include "vabstractapplication.h"
#include "../vmisc/def.h" #include "../vmisc/def.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
# include <QLockFile>
#endif
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
VAbstractApplication::VAbstractApplication(int &argc, char **argv) VAbstractApplication::VAbstractApplication(int &argc, char **argv)
:QApplication(argc, argv), :QApplication(argc, argv),
@ -116,43 +112,3 @@ double VAbstractApplication::fromPixel(double pix) const
{ {
return FromPixel(pix, _patternUnit); return FromPixel(pix, _patternUnit);
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
//---------------------------------------------------------------------------------------------------------------------
bool VAbstractApplication::TryLock(QLockFile *lock)
{
if (lock == nullptr)
{
return false;
}
if (lock->tryLock())
{
return true;
}
else
{
if (lock->error() == QLockFile::LockFailedError)
{
// This happens if a stale lock file exists and another process uses that PID.
// Try removing the stale file, which will fail if a real process is holding a
// file-level lock. A false error is more problematic than not locking properly
// on corner-case systems.
if (lock->removeStaleLockFile() == false || lock->tryLock() == false)
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
return false;
}
}
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)

View File

@ -33,15 +33,13 @@
#include <QGraphicsScene> #include <QGraphicsScene>
#include "def.h" #include "def.h"
#include "vsettings.h" #include "vsettings.h"
#include "vlockguard.h"
class VAbstractApplication;// use in define class VAbstractApplication;// use in define
class VTranslateVars; class VTranslateVars;
class VAbstractPattern; class VAbstractPattern;
class VMainGraphicsView; class VMainGraphicsView;
class QUndoStack; class QUndoStack;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
class QLockFile;
#endif
#if defined(qApp) #if defined(qApp)
#undef qApp #undef qApp
@ -89,10 +87,6 @@ public:
QUndoStack *getUndoStack() const; QUndoStack *getUndoStack() const;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
static bool TryLock(QLockFile *lock);
#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
protected: protected:
QUndoStack *undoStack; QUndoStack *undoStack;

200
src/libs/vmisc/vlockguard.h Normal file
View File

@ -0,0 +1,200 @@
/************************************************************************
**
** @file VLockGuard.h
** @author Alex Zaharov <alexzkhr@gmail.com>
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 14 9, 2015
**
** @brief
** @copyright
** This source code is part of the Valentine project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2015 Valentina project
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VLOCKGUARD_H
#define VLOCKGUARD_H
#include <QString>
#include <stdint.h>
#include <memory>
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
#include <QLockFile>
#define PEDANT_COMPILER ,lock(nullptr)
#else
#define PEDANT_COMPILER
#warning To have lock-file support you must use Qt 5.1+. Expect collissions when run 2 copies of the program.
#endif
/*@brief
* This class creates Guarded object if and only if lock file taken. It keeps shared_ptr to object and lock-file.
* Can use optional object allocator and deleter.
*
* On older Qt lock assumed always taken and compile-time warning is shown.
*
*/
template <typename Guarded>
class VLockGuard
{
public:
VLockGuard(const QString& lockName, int stale = 0, int timeout = 0);
template <typename Alloc>
VLockGuard(const QString& lockName, Alloc a, int stale = 0, int timeout=0);
template <typename Alloc, typename Delete>
VLockGuard(const QString& lockName, Alloc a, Delete d, int stale = 0, int timeout=0);
const std::shared_ptr<Guarded> &GetProtected() const;
int GetLockError() const;
bool IsLocked() const;
private:
Q_DISABLE_COPY(VLockGuard<Guarded>)
std::shared_ptr<Guarded> holder;
int lockError;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
std::shared_ptr<QLockFile> lock;
#endif
bool TryLock(const QString &lockName, int stale, int timeout);
};
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded>
VLockGuard<Guarded>::VLockGuard(const QString &lockName, int stale, int timeout)
: holder(nullptr), lockError(0) PEDANT_COMPILER
{
if (TryLock(lockName, stale, timeout))
{
holder.reset(new Guarded());
}
}
//---------------------------------------------------------------------------------------------------------------------
//using allocator lambdas seems logically better than supplying pointer, because we will take ownership of allocated
//object
template <typename Guarded> template <typename Alloc>
VLockGuard<Guarded>::VLockGuard(const QString& lockName, Alloc a, int stale, int timeout)
: holder(nullptr), lockError(0) PEDANT_COMPILER
{
if (TryLock(lockName, stale, timeout))
{
holder.reset(a());
}
}
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded> template <typename Alloc, typename Delete>
VLockGuard<Guarded>::VLockGuard(const QString& lockName, Alloc a, Delete d, int stale, int timeout)
: holder(nullptr), lockError(0) PEDANT_COMPILER
{
if (TryLock(lockName, stale, timeout))
{
holder.reset(a(), d);
}
}
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded>
const std::shared_ptr<Guarded> &VLockGuard<Guarded>::GetProtected() const
{
return holder;
}
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded>
int VLockGuard<Guarded>::GetLockError() const
{
return lockError;
}
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded>
bool VLockGuard<Guarded>::IsLocked() const
{
return holder != nullptr;
}
//---------------------------------------------------------------------------------------------------------------------
template <typename Guarded>
bool VLockGuard<Guarded>::TryLock(const QString &lockName, int stale, int timeout)
{
bool res = true;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
lock.reset(new QLockFile(lockName));
lock->setStaleLockTime(stale);
for (int i = 0; i < 2 && !lock->tryLock(timeout); i++)
{
if (QLockFile::LockFailedError != lock->error())
{
break;
}
else
{
// This happens if a stale lock file exists and another process uses that PID.
// Try removing the stale file, which will fail if a real process is holding a
// file-level lock. A false error is more problematic than not locking properly
// on corner-case systems.
lock->removeStaleLockFile();
lock->tryLock(timeout);
}
}
res = QLockFile::NoError == (lockError = lock->error());
if (!res)
{
lock.reset();
}
#endif
return res;
}
#undef PEDANT_COMPILER
//use pointer and function below to persistent things like class-member, because lock is taken by constructor
//helper functions allow to write shorter creating and setting new lock-pointer
//new C++11 - "template typedef" http://stackoverflow.com/questions/2795023/c-template-typedef
template <typename Guarded>
using VLockGuardPtr = std::shared_ptr<VLockGuard<Guarded>>;
template <typename Guarded>
void VlpCreateLock(VLockGuardPtr<Guarded>& r, const QString& lockName, int stale = 0, int timeout = 0)
{
r.reset(new VLockGuard<Guarded>(lockName, stale, timeout));
}
template <typename Guarded, typename Alloc>
void VlpCreateLock(VLockGuardPtr<Guarded>& r, const QString& lockName, Alloc a, int stale = 0, int timeout = 0)
{
r.reset(new VLockGuard<Guarded>(lockName, a, stale, timeout));
}
template <typename Guarded, typename Alloc, typename Del>
void VlpCreateLock(VLockGuardPtr<Guarded>& r, const QString& lockName, Alloc a, Del d, int stale = 0, int timeout = 0)
{
r.reset(new VLockGuard<Guarded>(lockName, a, d, stale, timeout));
}
#endif // VLOCKGUARD_H

View File

@ -26,4 +26,5 @@ HEADERS += \
$$PWD/projectversion.h \ $$PWD/projectversion.h \
$$PWD/vcommonsettings.h \ $$PWD/vcommonsettings.h \
$$PWD/vtapesettings.h \ $$PWD/vtapesettings.h \
debugbreak.h $$PWD/debugbreak.h \
$$PWD/vlockguard.h