mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-12 23:35:33 +08:00
refs #495 Workaround lack of atomic operations on std::shared_ptr in GCC 4.9.
This commit is contained in:
23
src/blackmisc/lockfree.cpp
Normal file
23
src/blackmisc/lockfree.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* Copyright (C) 2015
|
||||||
|
* swift project Community / Contributors
|
||||||
|
*
|
||||||
|
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||||
|
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||||
|
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||||
|
* contained in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lockfree.h"
|
||||||
|
|
||||||
|
namespace BlackMisc
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
// this is only needed for GCC <= 4.9, but we define it for all compilers to avoid warning about empty cpp file
|
||||||
|
QMutex *atomicSharedPtrMutex()
|
||||||
|
{
|
||||||
|
static QMutex mutex(QMutex::Recursive);
|
||||||
|
return &mutex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "blackmisc/variant.h"
|
#include "blackmisc/variant.h"
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -33,6 +34,45 @@ namespace BlackMisc
|
|||||||
template <typename>
|
template <typename>
|
||||||
class LockFree;
|
class LockFree;
|
||||||
|
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
//! \private
|
||||||
|
BLACKMISC_EXPORT QMutex *atomicSharedPtrMutex();
|
||||||
|
|
||||||
|
//! \private
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<T> atomic_load(const std::shared_ptr<T>* ptr)
|
||||||
|
{
|
||||||
|
#if defined(Q_CC_GNU) && __GNUC__ <= 4
|
||||||
|
QMutexLocker lock(BlackMisc::Private::atomicSharedPtrMutex());
|
||||||
|
return *ptr;
|
||||||
|
#else
|
||||||
|
return std::atomic_load(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \private
|
||||||
|
template <typename T>
|
||||||
|
bool atomic_compare_exchange_strong(std::shared_ptr<T>* ptr, std::shared_ptr<T>* exp, std::shared_ptr<T> des)
|
||||||
|
{
|
||||||
|
#if defined(Q_CC_GNU) && __GNUC__ <= 4
|
||||||
|
std::shared_ptr<T> tmp;
|
||||||
|
QMutexLocker lock(BlackMisc::Private::atomicSharedPtrMutex());
|
||||||
|
if (*ptr == *exp && ! ptr->owner_before(*exp) && ! exp->owner_before(*ptr))
|
||||||
|
{
|
||||||
|
tmp = std::move(*ptr);
|
||||||
|
*ptr = std::move(des);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tmp = std::move(*exp);
|
||||||
|
*exp = *ptr;
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return std::atomic_compare_exchange_strong(ptr, exp, des);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Return value of LockFree::read(). Allows any one thread to safely read from the lock-free object.
|
* Return value of LockFree::read(). Allows any one thread to safely read from the lock-free object.
|
||||||
*/
|
*/
|
||||||
@@ -103,7 +143,7 @@ namespace BlackMisc
|
|||||||
~LockFreeUniqueWriter() Q_DECL_NOEXCEPT
|
~LockFreeUniqueWriter() Q_DECL_NOEXCEPT
|
||||||
{
|
{
|
||||||
if (m_ptr.use_count() == 0) { return; } // *this has been moved from
|
if (m_ptr.use_count() == 0) { return; } // *this has been moved from
|
||||||
bool success = std::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr));
|
bool success = Private::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr));
|
||||||
Q_ASSERT_X(success, qPrintable(name()), "UniqueWriter detected simultaneous writes");
|
Q_ASSERT_X(success, qPrintable(name()), "UniqueWriter detected simultaneous writes");
|
||||||
Q_UNUSED(success);
|
Q_UNUSED(success);
|
||||||
}
|
}
|
||||||
@@ -149,13 +189,13 @@ namespace BlackMisc
|
|||||||
operator bool()
|
operator bool()
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(m_ptr.use_count() > 0, qPrintable(name()), "SharedWriter tried to commit changes twice");
|
Q_ASSERT_X(m_ptr.use_count() > 0, qPrintable(name()), "SharedWriter tried to commit changes twice");
|
||||||
if (std::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr)))
|
if (Private::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr)))
|
||||||
{
|
{
|
||||||
m_ptr.reset();
|
m_ptr.reset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
QThread::msleep(1);
|
QThread::msleep(1);
|
||||||
m_old = std::atomic_load(m_now);
|
m_old = Private::atomic_load(m_now);
|
||||||
m_ptr = std::make_shared<T>(*m_old);
|
m_ptr = std::make_shared<T>(*m_old);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -222,19 +262,19 @@ namespace BlackMisc
|
|||||||
//! Return an object which can read the current value.
|
//! Return an object which can read the current value.
|
||||||
LockFreeReader<const T> read() const
|
LockFreeReader<const T> read() const
|
||||||
{
|
{
|
||||||
return { std::atomic_load(&m_ptr) };
|
return { Private::atomic_load(&m_ptr) };
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Return an object which can write a new value, as long as there are no other writes.
|
//! Return an object which can write a new value, as long as there are no other writes.
|
||||||
LockFreeUniqueWriter<T> uniqueWrite()
|
LockFreeUniqueWriter<T> uniqueWrite()
|
||||||
{
|
{
|
||||||
return { std::atomic_load(&m_ptr), &m_ptr };
|
return { Private::atomic_load(&m_ptr), &m_ptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Return an object which can write a new value, even if there are other writes.
|
//! Return an object which can write a new value, even if there are other writes.
|
||||||
LockFreeSharedWriter<T> sharedWrite()
|
LockFreeSharedWriter<T> sharedWrite()
|
||||||
{
|
{
|
||||||
return { std::atomic_load(&m_ptr), &m_ptr };
|
return { Private::atomic_load(&m_ptr), &m_ptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Pass the current value to the functor inspector, and return whatever inspector returns.
|
//! Pass the current value to the functor inspector, and return whatever inspector returns.
|
||||||
|
|||||||
Reference in New Issue
Block a user