[BUG_FIXED] Lock some operations for data integrality.
Use mutex of Yuni library to lock critical operation for the compatibility of windows xp sp2. For more info of Yuni library: https://github.com/libyuni
This commit is contained in:
parent
acb713d9e6
commit
9ad71107e9
|
@ -25,19 +25,24 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
#include "LongRunningOperation.h"
|
||||
#include "mutex.h"
|
||||
|
||||
using namespace Yuni;
|
||||
|
||||
|
||||
// Due to retro-compatibility reason (with xp sp2), we use ::CreateMutex() instead of std::recursive_mutex
|
||||
// TODO : use Windows Mutex to lock/unlock operations
|
||||
|
||||
|
||||
LongRunningOperation::LongRunningOperation()
|
||||
{
|
||||
//_operationMutex.lock();
|
||||
Mutex::ClassLevelLockable<LongRunningOperation>::mutex.lock();
|
||||
}
|
||||
|
||||
|
||||
LongRunningOperation::~LongRunningOperation()
|
||||
{
|
||||
//_operationMutex.unlock();
|
||||
}
|
||||
Mutex::ClassLevelLockable<LongRunningOperation>::mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
// YUNI's default license is the GNU Lesser Public License (LGPL), with some
|
||||
// exclusions (see below). This basically means that you can get the full source
|
||||
// code for nothing, so long as you adhere to a few rules.
|
||||
//
|
||||
// Under the LGPL you may use YUNI for any purpose you wish, and modify it if you
|
||||
// require, as long as you:
|
||||
//
|
||||
// Pass on the (modified) YUNI source code with your software, with original
|
||||
// copyrights intact :
|
||||
// * If you distribute electronically, the source can be a separate download
|
||||
// (either from your own site if you modified YUNI, or to the official YUNI
|
||||
// website if you used an unmodified version) – just include a link in your
|
||||
// documentation
|
||||
// * If you distribute physical media, the YUNI source that you used to build
|
||||
// your application should be included on that media
|
||||
// Make it clear where you have customised it.
|
||||
//
|
||||
// In addition to the LGPL license text, the following exceptions / clarifications
|
||||
// to the LGPL conditions apply to YUNI:
|
||||
//
|
||||
// * Making modifications to YUNI configuration files, build scripts and
|
||||
// configuration headers such as yuni/platform.h in order to create a
|
||||
// customised build setup of YUNI with the otherwise unmodified source code,
|
||||
// does not constitute a derived work
|
||||
// * Building against YUNI headers which have inlined code does not constitute a
|
||||
// derived work
|
||||
// * Code which subclasses YUNI classes outside of the YUNI libraries does not
|
||||
// form a derived work
|
||||
// * Statically linking the YUNI libraries into a user application does not make
|
||||
// the user application a derived work.
|
||||
// * Using source code obsfucation on the YUNI source code when distributing it
|
||||
// is not permitted.
|
||||
// As per the terms of the LGPL, a "derived work" is one for which you have to
|
||||
// distribute source code for, so when the clauses above define something as not
|
||||
// a derived work, it means you don't have to distribute source code for it.
|
||||
// However, the original YUNI source code with all modifications must always be
|
||||
// made available.
|
||||
|
||||
#include "mutex.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
|
||||
#if YUNI_ATOMIC_MUST_USE_MUTEX != 0
|
||||
#warning Atomic types must ue mutex. the implementation should be checked YUNI_OS_GCC_VERSION
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Yuni
|
||||
{
|
||||
|
||||
enum // anonymous
|
||||
{
|
||||
/*!
|
||||
** \brief The spin count for the critical section object
|
||||
**
|
||||
** On single-processor systems, the spin count is ignored and the critical section
|
||||
** spin count is set to 0 (zero). On multiprocessor systems, if the critical section
|
||||
** is unavailable, the calling thread spinsdwSpinCount times before performing a
|
||||
** wait operation on a semaphore associated with the critical section. If the critical
|
||||
** section becomes free during the spin operation, the calling thread avoids the
|
||||
** wait operation.
|
||||
** \see http://msdn.microsoft.com/en-us/library/ms683476%28v=vs.85%29.aspx
|
||||
*/
|
||||
spinCount = 3000,
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void Mutex::destroy()
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
DeleteCriticalSection(&pSection);
|
||||
# else
|
||||
switch (::pthread_mutex_destroy(&pLock))
|
||||
{
|
||||
case 0: // Ok good
|
||||
{
|
||||
break;
|
||||
}
|
||||
// If an error happens, we will let the program continue but
|
||||
// it can becaome ugly around here...
|
||||
case EBUSY:
|
||||
{
|
||||
std::cerr << "\nattempt to destroy a mutex while it is locked or referenced\n";
|
||||
assert(false and "attempt to destroy a mutex while it is locked or referenced");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::cerr << "\nfailed to destroy a mutex\n";
|
||||
assert(false and "\nfailed to destroy a mutex\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
::pthread_mutexattr_destroy(&pAttr);
|
||||
# endif
|
||||
# endif // no thread safe
|
||||
}
|
||||
|
||||
|
||||
inline void Mutex::copy(const Mutex& rhs)
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
InitializeCriticalSectionAndSpinCount(&pSection, spinCount);
|
||||
(void) rhs; // unused
|
||||
# else
|
||||
::pthread_mutexattr_init(&pAttr);
|
||||
int type; // = PTHREAD_MUTEX_NORMAL;
|
||||
if (0 == ::pthread_mutexattr_gettype(&rhs.pAttr, &type))
|
||||
{
|
||||
if (PTHREAD_MUTEX_RECURSIVE == type)
|
||||
{
|
||||
# if defined(YUNI_OS_DARWIN) or defined(YUNI_OS_FREEBSD) or defined(YUNI_OS_SOLARIS) or defined(YUNI_OS_SUNOS) or defined(YUNI_OS_HAIKU) or defined(YUNI_OS_CYGWIN)
|
||||
::pthread_mutexattr_settype(&pAttr, PTHREAD_MUTEX_RECURSIVE);
|
||||
# else
|
||||
::pthread_mutexattr_settype(&pAttr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
::pthread_mutex_init(& pLock, &pAttr);
|
||||
# endif
|
||||
# else
|
||||
(void) rhs; // unused
|
||||
# endif // no thread safe
|
||||
}
|
||||
|
||||
|
||||
|
||||
Mutex::Mutex(const Mutex& rhs)
|
||||
{
|
||||
copy(rhs);
|
||||
}
|
||||
|
||||
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
Mutex::Mutex(bool recursive)
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
(void) recursive; // already recursive on Windows
|
||||
InitializeCriticalSectionAndSpinCount(&pSection, spinCount);
|
||||
# else
|
||||
::pthread_mutexattr_init(&pAttr);
|
||||
if (recursive)
|
||||
{
|
||||
# if defined(YUNI_OS_DARWIN) or defined(YUNI_OS_FREEBSD) or defined(YUNI_OS_SOLARIS) or defined(YUNI_OS_SUNOS) or defined(YUNI_OS_HAIKU) or defined(YUNI_OS_CYGWIN)
|
||||
::pthread_mutexattr_settype(&pAttr, PTHREAD_MUTEX_RECURSIVE);
|
||||
# else
|
||||
::pthread_mutexattr_settype(&pAttr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
# endif
|
||||
}
|
||||
::pthread_mutex_init(&pLock, &pAttr);
|
||||
# endif
|
||||
# else
|
||||
(void) recursive;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
Mutex& Mutex::operator = (const Mutex& rhs)
|
||||
{
|
||||
// We will recreate the mutex
|
||||
destroy();
|
||||
copy(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Yuni
|
|
@ -0,0 +1,234 @@
|
|||
// YUNI's default license is the GNU Lesser Public License (LGPL), with some
|
||||
// exclusions (see below). This basically means that you can get the full source
|
||||
// code for nothing, so long as you adhere to a few rules.
|
||||
//
|
||||
// Under the LGPL you may use YUNI for any purpose you wish, and modify it if you
|
||||
// require, as long as you:
|
||||
//
|
||||
// Pass on the (modified) YUNI source code with your software, with original
|
||||
// copyrights intact :
|
||||
// * If you distribute electronically, the source can be a separate download
|
||||
// (either from your own site if you modified YUNI, or to the official YUNI
|
||||
// website if you used an unmodified version) – just include a link in your
|
||||
// documentation
|
||||
// * If you distribute physical media, the YUNI source that you used to build
|
||||
// your application should be included on that media
|
||||
// Make it clear where you have customised it.
|
||||
//
|
||||
// In addition to the LGPL license text, the following exceptions / clarifications
|
||||
// to the LGPL conditions apply to YUNI:
|
||||
//
|
||||
// * Making modifications to YUNI configuration files, build scripts and
|
||||
// configuration headers such as yuni/platform.h in order to create a
|
||||
// customised build setup of YUNI with the otherwise unmodified source code,
|
||||
// does not constitute a derived work
|
||||
// * Building against YUNI headers which have inlined code does not constitute a
|
||||
// derived work
|
||||
// * Code which subclasses YUNI classes outside of the YUNI libraries does not
|
||||
// form a derived work
|
||||
// * Statically linking the YUNI libraries into a user application does not make
|
||||
// the user application a derived work.
|
||||
// * Using source code obsfucation on the YUNI source code when distributing it
|
||||
// is not permitted.
|
||||
// As per the terms of the LGPL, a "derived work" is one for which you have to
|
||||
// distribute source code for, so when the clauses above define something as not
|
||||
// a derived work, it means you don't have to distribute source code for it.
|
||||
// However, the original YUNI source code with all modifications must always be
|
||||
// made available.
|
||||
|
||||
#pragma once
|
||||
#define YUNI_OS_WINDOWS
|
||||
#define YUNI_HAS_CPP_MOVE
|
||||
#define YUNI_DECL
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
namespace Yuni
|
||||
{
|
||||
|
||||
/*!
|
||||
** \brief Mechanism to avoid the simultaneous use of a common resource
|
||||
**
|
||||
** \ingroup Threads
|
||||
*/
|
||||
class YUNI_DECL Mutex final
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
** \brief A class-level locking mechanism
|
||||
**
|
||||
** A class-level locking operation locks all objects in a given class during that operation
|
||||
*/
|
||||
template<class T>
|
||||
class ClassLevelLockable
|
||||
{
|
||||
public:
|
||||
//! A dedicated mutex for the class T
|
||||
static Mutex mutex;
|
||||
|
||||
}; // class ClassLevelLockable
|
||||
|
||||
|
||||
public:
|
||||
//! \name Constructor & Destructor
|
||||
//@{
|
||||
/*!
|
||||
** \brief Default constructor
|
||||
**
|
||||
** Recursive by default to keep homogeneous behavior between
|
||||
** platforms.
|
||||
*/
|
||||
explicit Mutex(bool recursive = true);
|
||||
/*!
|
||||
** \brief Copy constructor
|
||||
**
|
||||
** This constructor does actually nothing but it allows the compilation
|
||||
** of other classes which would implement a copy constructor
|
||||
*/
|
||||
Mutex(const Mutex&);
|
||||
|
||||
# ifdef YUNI_HAS_CPP_MOVE
|
||||
// an OS's native mutex must have invariant address and thus can not be moved
|
||||
Mutex(Mutex&&) = delete;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
** \brief Destructor
|
||||
*/
|
||||
~Mutex();
|
||||
//@}
|
||||
|
||||
//! \name Lock & Unlock
|
||||
//@{
|
||||
/*!
|
||||
** \brief Lock the mutex
|
||||
*/
|
||||
void lock();
|
||||
|
||||
/*!
|
||||
** \brief Try to lock the mutex
|
||||
**
|
||||
** \return True if the mutex has been locked, false otherwise
|
||||
*/
|
||||
bool trylock();
|
||||
|
||||
/*!
|
||||
** \brief Release the lock
|
||||
*/
|
||||
void unlock();
|
||||
//@}
|
||||
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifndef YUNI_OS_WINDOWS
|
||||
//! \name Native
|
||||
//@{
|
||||
//! Get the original PThread mutex
|
||||
::pthread_mutex_t& pthreadMutex();
|
||||
//! Get the original PThread mutex (const)
|
||||
const ::pthread_mutex_t& pthreadMutex() const;
|
||||
//@}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
//! Operator = (do nothing)
|
||||
Mutex& operator = (const Mutex&);
|
||||
# ifdef YUNI_HAS_CPP_MOVE
|
||||
// an OS's native mutex must have invariant address and thus can not be moved
|
||||
Mutex& operator = (Mutex&&) = delete;
|
||||
#endif
|
||||
//@}
|
||||
|
||||
|
||||
private:
|
||||
//! Destroy the current mutex
|
||||
inline void destroy();
|
||||
//! Create the mutex with settings from another mutex
|
||||
inline void copy(const Mutex& rhs);
|
||||
|
||||
private:
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
//! The critical section
|
||||
CRITICAL_SECTION pSection;
|
||||
# else
|
||||
//! The PThread mutex
|
||||
::pthread_mutex_t pLock;
|
||||
::pthread_mutexattr_t pAttr;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
}; // class Mutex
|
||||
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
** \brief Locks a mutex in the constructor and unlocks it in the destructor (RAII).
|
||||
**
|
||||
** This class is especially usefull for `get` accessor` and/or returned values
|
||||
** which have to be thread-safe.
|
||||
** This is a very common C++ idiom, known as "Resource Acquisition Is Initialization" (RAII).
|
||||
**
|
||||
** \code
|
||||
** class Foo
|
||||
** {
|
||||
** public:
|
||||
** Foo() : pValue(42) {}
|
||||
** ~Foo() {}
|
||||
** int getValue()
|
||||
** {
|
||||
** MutexLocker locker(pMutex);
|
||||
** return pValue;
|
||||
** }
|
||||
** void setValue(const int i)
|
||||
** {
|
||||
** pMutex.lock();
|
||||
** pValue = i;
|
||||
** pMutex.unlock();
|
||||
** }
|
||||
** private:
|
||||
** int pValue;
|
||||
** Mutex pMutex;
|
||||
** };
|
||||
** \endcode
|
||||
*/
|
||||
class MutexLocker final
|
||||
{
|
||||
public:
|
||||
//! \name Constructor & Destructor
|
||||
//@{
|
||||
/*!
|
||||
** \brief Constructor
|
||||
**
|
||||
** \param m The mutex to lock
|
||||
*/
|
||||
MutexLocker(Mutex& m);
|
||||
//! Destructor
|
||||
~MutexLocker();
|
||||
//@}
|
||||
|
||||
MutexLocker& operator = (const MutexLocker&) = delete;
|
||||
|
||||
private:
|
||||
//! Reference to the real mutex
|
||||
Mutex& pMutex;
|
||||
|
||||
}; // MutexLocker
|
||||
|
||||
|
||||
|
||||
|
||||
//! All mutexes for each class
|
||||
template<class T> Mutex Mutex::ClassLevelLockable<T>::mutex;
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Yuni
|
||||
|
||||
# include "mutex.hxx"
|
|
@ -0,0 +1,116 @@
|
|||
// YUNI's default license is the GNU Lesser Public License (LGPL), with some
|
||||
// exclusions (see below). This basically means that you can get the full source
|
||||
// code for nothing, so long as you adhere to a few rules.
|
||||
|
||||
// Under the LGPL you may use YUNI for any purpose you wish, and modify it if you
|
||||
// require, as long as you:
|
||||
//
|
||||
// Pass on the (modified) YUNI source code with your software, with original
|
||||
// copyrights intact :
|
||||
// * If you distribute electronically, the source can be a separate download
|
||||
// (either from your own site if you modified YUNI, or to the official YUNI
|
||||
// website if you used an unmodified version) – just include a link in your
|
||||
// documentation
|
||||
// * If you distribute physical media, the YUNI source that you used to build
|
||||
// your application should be included on that media
|
||||
// Make it clear where you have customised it.
|
||||
//
|
||||
// In addition to the LGPL license text, the following exceptions / clarifications
|
||||
// to the LGPL conditions apply to YUNI:
|
||||
//
|
||||
// * Making modifications to YUNI configuration files, build scripts and
|
||||
// configuration headers such as yuni/platform.h in order to create a
|
||||
// customised build setup of YUNI with the otherwise unmodified source code,
|
||||
// does not constitute a derived work
|
||||
// * Building against YUNI headers which have inlined code does not constitute a
|
||||
// derived work
|
||||
// * Code which subclasses YUNI classes outside of the YUNI libraries does not
|
||||
// form a derived work
|
||||
// * Statically linking the YUNI libraries into a user application does not make
|
||||
// the user application a derived work.
|
||||
// * Using source code obsfucation on the YUNI source code when distributing it
|
||||
// is not permitted.
|
||||
// As per the terms of the LGPL, a "derived work" is one for which you have to
|
||||
// distribute source code for, so when the clauses above define something as not
|
||||
// a derived work, it means you don't have to distribute source code for it.
|
||||
// However, the original YUNI source code with all modifications must always be
|
||||
// made available.
|
||||
|
||||
#pragma once
|
||||
#include "mutex.h"
|
||||
|
||||
|
||||
|
||||
namespace Yuni
|
||||
{
|
||||
|
||||
inline void Mutex::lock()
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
EnterCriticalSection(&pSection);
|
||||
# else
|
||||
::pthread_mutex_lock(&pLock);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
inline bool Mutex::trylock()
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
return (0 != TryEnterCriticalSection(&pSection));
|
||||
# else
|
||||
return (0 == ::pthread_mutex_trylock(&pLock));
|
||||
# endif
|
||||
# else
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
inline void Mutex::unlock()
|
||||
{
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifdef YUNI_OS_WINDOWS
|
||||
LeaveCriticalSection(&pSection);
|
||||
# else
|
||||
::pthread_mutex_unlock(&pLock);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
# ifndef YUNI_NO_THREAD_SAFE
|
||||
# ifndef YUNI_OS_WINDOWS
|
||||
inline pthread_mutex_t& Mutex::pthreadMutex()
|
||||
{
|
||||
return pLock;
|
||||
}
|
||||
|
||||
inline const pthread_mutex_t& Mutex::pthreadMutex() const
|
||||
{
|
||||
return pLock;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
inline MutexLocker::MutexLocker(Mutex& m) :
|
||||
pMutex(m)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
|
||||
inline MutexLocker::~MutexLocker()
|
||||
{
|
||||
pMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Yuni
|
|
@ -139,6 +139,7 @@ copy ..\src\contextMenu.xml ..\bin\contextMenu.xml
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\MISC\Common\LongRunningOperation.cpp" />
|
||||
<ClCompile Include="..\src\MISC\Common\mutex.cpp" />
|
||||
<ClCompile Include="..\src\WinControls\AboutDlg\AboutDlg.cpp" />
|
||||
<ClCompile Include="..\src\WinControls\AnsiCharPanel\ansiCharPanel.cpp" />
|
||||
<ClCompile Include="..\src\ScitillaComponent\AutoCompletion.cpp" />
|
||||
|
@ -409,6 +410,8 @@ copy ..\src\contextMenu.xml ..\bin\contextMenu.xml
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\MISC\Common\LongRunningOperation.h" />
|
||||
<ClInclude Include="..\src\MISC\Common\mutex.h" />
|
||||
<ClInclude Include="..\src\MISC\Common\mutex.hxx" />
|
||||
<ClInclude Include="..\src\ScitillaComponent\resource.h" />
|
||||
<ClInclude Include="..\src\WinControls\AboutDlg\AboutDlg.h" />
|
||||
<ClInclude Include="..\src\WinControls\AnsiCharPanel\ansiCharPanel.h" />
|
||||
|
|
Loading…
Reference in New Issue