refs #657 Fixed race condition in synchronize().

This commit is contained in:
Mathew Sutcliffe
2016-05-20 01:25:05 +01:00
parent 6aa67f638a
commit f523197dfd
2 changed files with 25 additions and 2 deletions

View File

@@ -28,6 +28,7 @@
#include <Qt> #include <Qt>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <chrono>
namespace BlackMisc namespace BlackMisc
{ {
@@ -107,10 +108,18 @@ namespace BlackMisc
bool CDataCache::synchronize(const QString &key) bool CDataCache::synchronize(const QString &key)
{ {
constexpr auto timeout = std::chrono::seconds(1);
constexpr auto ready = std::future_status::ready;
constexpr auto zero = std::chrono::seconds::zero();
auto future = m_revision.promiseLoadedValue(key, getTimestampSync(key)); auto future = m_revision.promiseLoadedValue(key, getTimestampSync(key));
if (future.valid()) if (future.valid())
{ {
future.wait(); std::future_status s {};
do { s = future.wait_for(timeout); } while (s != ready && m_revision.isNewerValueAvailable(key, getTimestampSync(key)));
if (s != ready) { s = future.wait_for(zero); }
if (s != ready) { return false; }
try { future.get(); } catch (const std::future_error &) { return false; } // broken promise
return true; return true;
} }
return false; return false;
@@ -285,7 +294,6 @@ namespace BlackMisc
Q_ASSERT(! m_updateInProgress); Q_ASSERT(! m_updateInProgress);
Q_ASSERT(! m_lockFile.isLocked()); Q_ASSERT(! m_lockFile.isLocked());
Q_ASSERT(m_promises.empty());
if (! m_lockFile.lock()) if (! m_lockFile.lock())
{ {
@@ -396,6 +404,7 @@ namespace BlackMisc
m_updateInProgress = false; m_updateInProgress = false;
m_pendingRead = false; m_pendingRead = false;
m_pendingWrite = false; m_pendingWrite = false;
breakPromises();
m_lockFile.unlock(); m_lockFile.unlock();
} }
@@ -451,6 +460,17 @@ namespace BlackMisc
return std::move(m_promises); // move into the return value, so m_promises becomes empty return std::move(m_promises); // move into the return value, so m_promises becomes empty
} }
void CDataCacheRevision::breakPromises()
{
QMutexLocker lock(&m_mutex);
if (! m_promises.empty())
{
CLogMessage(this).debug() << "Breaking" << m_promises.size() << "promises";
m_promises.clear();
}
}
QString CDataCacheRevision::timestampsAsString() const QString CDataCacheRevision::timestampsAsString() const
{ {
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);

View File

@@ -126,6 +126,9 @@ namespace BlackMisc
//! Returns (by move) the container of promises to load values. //! Returns (by move) the container of promises to load values.
std::vector<std::promise<void>> loadedValuePromises(); std::vector<std::promise<void>> loadedValuePromises();
//! Abandon all promises.
void breakPromises();
//! Keys with timestamps. //! Keys with timestamps.
QString timestampsAsString() const; QString timestampsAsString() const;