fixes
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#ifndef PIPROTECTEDVARIABLE_H
|
#ifndef PIPROTECTEDVARIABLE_H
|
||||||
#define PIPROTECTEDVARIABLE_H
|
#define PIPROTECTEDVARIABLE_H
|
||||||
|
|
||||||
|
#include "picout.h"
|
||||||
#include "pimutex.h"
|
#include "pimutex.h"
|
||||||
|
|
||||||
//! \~\ingroup Thread
|
//! \~\ingroup Thread
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class PIP_EXPORT PIProtectedVariable {
|
class PIP_EXPORT PIProtectedVariable {
|
||||||
public:
|
public:
|
||||||
|
PIProtectedVariable(T v = T()): var(std::move(v)) {}
|
||||||
|
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Pointer-like wrapper returned by \a getRef() while the protected value remains locked.
|
//! \~english Pointer-like wrapper returned by \a getRef() while the protected value remains locked.
|
||||||
//! \~russian Указателеподобная обертка, возвращаемая \a getRef(), пока защищенное значение остается заблокированным.
|
//! \~russian Указателеподобная обертка, возвращаемая \a getRef(), пока защищенное значение остается заблокированным.
|
||||||
@@ -44,17 +47,23 @@ public:
|
|||||||
public:
|
public:
|
||||||
//! \~\english Move constructor - transfers ownership of the lock.
|
//! \~\english Move constructor - transfers ownership of the lock.
|
||||||
//! \~russian Конструктор перемещения - передает владение блокировкой.
|
//! \~russian Конструктор перемещения - передает владение блокировкой.
|
||||||
Pointer(Pointer && other) noexcept: pv(other.pv), ownsLock(other.ownsLock) { other.ownsLock = false; }
|
Pointer(Pointer && other): pv(other.pv) { other.can_unlock = false; };
|
||||||
|
|
||||||
|
|
||||||
//! \~\english Move assignment is deleted - Pointer can only be moved once.
|
//! \~\english Move assignment - transfers ownership of the lock.
|
||||||
//! \~russian Оператор перемещения удален - Pointer можно переместить только один раз.
|
//! \~russian Оператор перемещения - передает владение блокировкой.
|
||||||
Pointer & operator=(Pointer &&) = delete;
|
Pointer & operator=(Pointer && other) {
|
||||||
|
pv = other.pv;
|
||||||
|
other.can_unlock = false;
|
||||||
|
};
|
||||||
|
|
||||||
//! \~\english Destroys wrapper and releases the mutex.
|
//! \~\english Destroys wrapper and releases the mutex.
|
||||||
//! \~russian Уничтожает обертку и освобождает мьютекс.
|
//! \~russian Уничтожает обертку и освобождает мьютекс.
|
||||||
~Pointer() {
|
~Pointer() {
|
||||||
if (ownsLock) pv.mutex.unlock();
|
if (can_unlock) {
|
||||||
|
pv.mutex.unlock();
|
||||||
|
piCout << "mutex.unlock()" << &(pv.mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \~english Returns pointer access to the protected value.
|
//! \~english Returns pointer access to the protected value.
|
||||||
@@ -66,11 +75,14 @@ public:
|
|||||||
T & operator*() { return pv.var; }
|
T & operator*() { return pv.var; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pointer() = delete;
|
explicit Pointer() = delete;
|
||||||
Pointer(PIProtectedVariable<T> & v): pv(v), ownsLock(true) {}
|
explicit Pointer(PIProtectedVariable<T> & v): pv(v) {
|
||||||
|
pv.mutex.lock();
|
||||||
|
piCout << "mutex.lock()" << &(pv.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
PIProtectedVariable<T> & pv;
|
PIProtectedVariable<T> & pv;
|
||||||
bool ownsLock = true;
|
bool can_unlock = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \~english Replaces the protected value with \a v.
|
//! \~english Replaces the protected value with \a v.
|
||||||
@@ -82,10 +94,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Locks the value and returns wrapper-based access to it.
|
//! \~english Locks the value and returns wrapper-based access to it.
|
||||||
//! \~russian Блокирует значение и возвращает обертку для доступа к нему.
|
//! \~russian Блокирует значение и возвращает обертку для доступа к нему.
|
||||||
Pointer getRef() {
|
Pointer getRef() { return Pointer(*this); }
|
||||||
mutex.lock();
|
|
||||||
return Pointer(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Returns a copy of the protected value.
|
//! \~english Returns a copy of the protected value.
|
||||||
//! \~russian Возвращает копию защищенного значения.
|
//! \~russian Возвращает копию защищенного значения.
|
||||||
@@ -104,7 +113,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
mutable PIMutex mutex;
|
mutable PIMutex mutex;
|
||||||
T var;
|
T var = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
main.cpp
21
main.cpp
@@ -20,6 +20,27 @@ inline PIByteArray SMBusTypeInfo_genHash(PIString n) {
|
|||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
PIProtectedVariable<double> pv(3.0);
|
||||||
|
piCout << pv.get();
|
||||||
|
{
|
||||||
|
auto ref = pv.getRef();
|
||||||
|
piCout << *ref;
|
||||||
|
*ref = 11.;
|
||||||
|
piCout << *ref;
|
||||||
|
}
|
||||||
|
piCout << pv.get();
|
||||||
|
{
|
||||||
|
auto ref = pv.getRef();
|
||||||
|
piCout << *ref;
|
||||||
|
*ref = 12.;
|
||||||
|
piCout << *ref;
|
||||||
|
auto ref2 = std::move(ref);
|
||||||
|
piCout << *ref2;
|
||||||
|
}
|
||||||
|
piCout << pv.get();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
PICrypt _crypt;
|
PICrypt _crypt;
|
||||||
// auto ba = PIFile::readAll("logo.png");
|
// auto ba = PIFile::readAll("logo.png");
|
||||||
PIString str = "hello!"_a;
|
PIString str = "hello!"_a;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ namespace {
|
|||||||
|
|
||||||
constexpr int THREAD_COUNT = 10;
|
constexpr int THREAD_COUNT = 10;
|
||||||
constexpr int ITERATIONS_PER_THREAD = 1000;
|
constexpr int ITERATIONS_PER_THREAD = 1000;
|
||||||
constexpr int WAIT_THREAD_TIME_MS = 1000;
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
@@ -229,7 +227,7 @@ TEST(PIProtectedVariable_ThreadSafety, MixedReadWriteOperations) {
|
|||||||
// Reader threads
|
// Reader threads
|
||||||
vector<thread> readers;
|
vector<thread> readers;
|
||||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||||
readers.emplace_back([&pv, &readCount, &invalidReads, &start, NUM_WRITER_ITERATIONS]() {
|
readers.emplace_back([&pv, &readCount, &invalidReads, &start]() {
|
||||||
while (!start.load()) {
|
while (!start.load()) {
|
||||||
this_thread::yield();
|
this_thread::yield();
|
||||||
}
|
}
|
||||||
@@ -468,8 +466,6 @@ TEST(PIProtectedVariable_Move, MoveConstructorTransfersLockOwnership) {
|
|||||||
PIProtectedVariable<int> pv;
|
PIProtectedVariable<int> pv;
|
||||||
pv.set(42);
|
pv.set(42);
|
||||||
|
|
||||||
atomic<int> unlockCount(0);
|
|
||||||
|
|
||||||
// We can't directly test unlock count without modifying the class,
|
// We can't directly test unlock count without modifying the class,
|
||||||
// but we can test the behavior: after move, only the target should unlock
|
// but we can test the behavior: after move, only the target should unlock
|
||||||
|
|
||||||
@@ -503,8 +499,6 @@ TEST(PIProtectedVariable_Move, SourceDoesNotUnlockAfterMove) {
|
|||||||
PIProtectedVariable<int> pv;
|
PIProtectedVariable<int> pv;
|
||||||
pv.set(42);
|
pv.set(42);
|
||||||
|
|
||||||
atomic<bool> deadlockOccurred(false);
|
|
||||||
|
|
||||||
// If source unlocked after move, we would get a double-unlock error
|
// If source unlocked after move, we would get a double-unlock error
|
||||||
// or undefined behavior. This test verifies that moving works correctly.
|
// or undefined behavior. This test verifies that moving works correctly.
|
||||||
|
|
||||||
@@ -569,15 +563,11 @@ TEST(PIProtectedVariable_Move, MoveWithRVODisabled) {
|
|||||||
// This test should be compiled with -fno-elide-constructors
|
// This test should be compiled with -fno-elide-constructors
|
||||||
// to ensure move constructor is actually called
|
// to ensure move constructor is actually called
|
||||||
|
|
||||||
PIProtectedVariable<int> pv;
|
PIProtectedVariable<int> pv(42);
|
||||||
pv.set(42);
|
|
||||||
|
|
||||||
auto createAndMove = [&pv]() -> decltype(pv.getRef()) {
|
auto ptr_src = pv.getRef();
|
||||||
auto ptr = pv.getRef();
|
*ptr_src = 99;
|
||||||
return std::move(ptr);
|
auto ptr = std::move(ptr_src);
|
||||||
};
|
|
||||||
|
|
||||||
auto ptr = createAndMove();
|
|
||||||
*ptr = 100;
|
*ptr = 100;
|
||||||
|
|
||||||
EXPECT_EQ(pv.get(), 100);
|
EXPECT_EQ(pv.get(), 100);
|
||||||
|
|||||||
Reference in New Issue
Block a user