diff --git a/libs/main/thread/pireadwritelock.cpp b/libs/main/thread/pireadwritelock.cpp
new file mode 100644
index 00000000..99ebb209
--- /dev/null
+++ b/libs/main/thread/pireadwritelock.cpp
@@ -0,0 +1,234 @@
+/*
+ PIP - Platform Independent Primitives
+ PIReadWriteLock, PIReadLocker, PIWriteLocker
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+//! \addtogroup Thread
+//! \{
+//! \class PIReadWriteLock pireadwritelock.h
+//!
+//! \~\brief
+//! \~english Read/Write lock
+//! \~russian Блокировка чтения/записи
+//!
+//!
+//! \~\details
+//! \~english \section PIReadWriteLock_sec0 Synopsis
+//! \~russian \section PIReadWriteLock_sec0 Краткий обзор
+//!
+//! \~english
+//! %PIReadWriteLock provides more complex critical code section defence between several threads.
+//! %PIReadWriteLock permit only one thread to modify data, besides multiple thread can read data
+//! simultaneously. Conatains methods:
+//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() and \a unlockRead().
+//!
+//! For automatic read and write locks use \a PIReadLocker and \a PIWriteLocker.
+//!
+//! \~russian
+//! %PIReadWriteLock предоставляет более сложную межпотоковую защиту критических секций кода.
+//! %PIReadWriteLock разрешает только одному потоку изменять данные, в то время как читать данные
+//! могут одновременно несколько потоков.
+//! Содержит методы:
+//! \a lockWrite(), \a tryLockWrite(), \a unlockWrite(), \a lockRead(), \a tryLockRead() и \a unlockRead().
+//!
+//! Для автоматической блокировки на чтение и запись используйте \a PIReadLocker и \a PIWriteLocker.
+//!
+//! \~english \section PIReadWriteLock_sec1 Usage
+//! \~russian \section PIReadWriteLock_sec1 Использование
+//!
+//! \~english
+//! When one thread lock for write with \a lockWrite(), all other threads (read and write) can`t access data until this thread
+//! call \a unlockWrite(). In this way, write lock works similar to mutex.
+//!
+//! On the other hand, several threads can simultaneously read data. In other words, \a lockRead() increase read threads counter
+//! and \a unlockRead() decrease. But thread can`t read data while other thread locked for write.
+//!
+//! \~russian
+//! Когда один поток блокирует запись с помощью функции \a lockWrite(), все остальные потоки (чтение и запись) не смогут получить
+//! доступ к данным, пока этот поток не вызовет \a unlockWrite(). Таким образом, блокировка записи работает аналогично мьютексу.
+//!
+//! С другой стороны, несколько потоков могут одновременно считывать данные. Другими словами, функция \a lockRead() увеличивает счетчик
+//! потоков чтения, а функция \a unlockRead() уменьшает. Но поток не может считывать данные, пока другой поток заблокирован для записи.
+//!
+//! \~\code
+//! \endcode
+//! \}
+
+
+//! \addtogroup Thread
+//! \{
+//! \class PIReadLocker pireadwritelock.h
+//!
+//! \~\brief
+//! \~english %PIReadWriteLock read autolocker
+//! \~russian Автоблокировщик на чтение %PIReadWriteLock
+//!
+//!
+//! \~\details
+//!
+//! \~english
+//! When a %PIReadLocker object is created, it lock %PIReadWriteLock for read, if "condition" \c true.
+//! When control leaves the scope in which the %PIReadLocker object was created,
+//! the %PIReadLocker is destructed and unlock for read, if "condition" was \c true.
+//!
+//! If "condition" \c false this class do nothing.
+//!
+//! The %PIReadLocker class is non-copyable.
+//!
+//! \~russian
+//! При создании экземпляра %PIReadLocker он блокирует %PIReadWriteLock на чтение, если "condition" \c true.
+//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на чтение,
+//! если "condition" был \c true.
+//!
+//! Если "condition" \c false, то этот объект ничего не делает.
+//!
+//! Класс %PIReadLocker некопируемый.
+//!
+//! \~\code
+//! // critical section start
+//! {
+//! PIReadLocker locker(rw_lock);
+//! // ... your read code here
+//! }
+//! // critical section end
+//! \endcode
+//! \}
+
+
+//! \addtogroup Thread
+//! \{
+//! \class PIWriteLocker pireadwritelock.h
+//!
+//! \~\brief
+//! \~english %PIReadWriteLock write autolocker
+//! \~russian Автоблокировщик на запись %PIReadWriteLock
+//!
+//!
+//! \~\details
+//!
+//! \~english
+//! When a %PIWriteLocker object is created, it lock %PIReadWriteLock for write, if "condition" \c true.
+//! When control leaves the scope in which the %PIWriteLocker object was created,
+//! the %PIWriteLocker is destructed and unlock for write, if "condition" was \c true.
+//!
+//! If "condition" \c false this class do nothing.
+//!
+//! The %PIWriteLocker class is non-copyable.
+//!
+//! \~russian
+//! При создании экземпляра %PIWriteLocker он блокирует %PIReadWriteLock на запись, если "condition" \c true.
+//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и освобождается блокировка на запись,
+//! если "condition" был \c true.
+//!
+//! Если "condition" \c false, то этот объект ничего не делает.
+//!
+//! Класс %PIWriteLocker некопируемый.
+//!
+//! \~\code
+//! // critical section start
+//! {
+//! PIWriteLocker locker(rw_lock);
+//! // ... your write code here
+//! }
+//! // critical section end
+//! \endcode
+//! \}
+
+
+#include "pireadwritelock.h"
+
+
+PIReadWriteLock::PIReadWriteLock() {}
+
+
+PIReadWriteLock::~PIReadWriteLock() {
+ var.notifyAll();
+}
+
+
+void PIReadWriteLock::lockWrite() {
+ PIMutexLocker _ml(mutex);
+ while (reading > 0 || writing) {
+ var.wait(mutex);
+ }
+ writing = true;
+}
+
+
+bool PIReadWriteLock::tryLockWrite() {
+ PIMutexLocker _ml(mutex);
+ if (reading > 0 || writing) return false;
+ writing = true;
+ return true;
+}
+
+
+bool PIReadWriteLock::tryLockWrite(PISystemTime timeout) {
+ PITimeMeasurer tm;
+ PIMutexLocker _ml(mutex);
+ while (reading > 0 || writing) {
+ PISystemTime remain = timeout - tm.elapsed();
+ if (remain.isNegative()) return false;
+ var.waitFor(mutex, remain);
+ }
+ writing = true;
+ return true;
+}
+
+
+void PIReadWriteLock::unlockWrite() {
+ PIMutexLocker _ml(mutex);
+ writing = false;
+ var.notifyAll();
+}
+
+
+void PIReadWriteLock::lockRead() {
+ PIMutexLocker _ml(mutex);
+ while (writing) {
+ var.wait(mutex);
+ }
+ ++reading;
+}
+
+
+bool PIReadWriteLock::tryLockRead() {
+ PIMutexLocker _ml(mutex);
+ if (writing) return false;
+ ++reading;
+ return true;
+}
+
+
+bool PIReadWriteLock::tryLockRead(PISystemTime timeout) {
+ PITimeMeasurer tm;
+ PIMutexLocker _ml(mutex);
+ while (writing) {
+ PISystemTime remain = timeout - tm.elapsed();
+ if (remain.isNegative()) return false;
+ var.waitFor(mutex, remain);
+ }
+ ++reading;
+ return true;
+}
+
+
+void PIReadWriteLock::unlockRead() {
+ PIMutexLocker _ml(mutex);
+ --reading;
+ var.notifyAll();
+}
diff --git a/libs/main/thread/pireadwritelock.h b/libs/main/thread/pireadwritelock.h
new file mode 100644
index 00000000..24b08a37
--- /dev/null
+++ b/libs/main/thread/pireadwritelock.h
@@ -0,0 +1,130 @@
+/*! \file pireadwritelock.h
+ * \ingroup Read/Write lock
+ * \~\brief
+ * \~english Read/Write lock
+ * \~russian Блокировка чтения/записи
+ */
+/*
+ PIP - Platform Independent Primitives
+ PIReadWriteLock, PIReadLocker, PIWriteLocker
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PIREADWRITELOCK_H
+#define PIREADWRITELOCK_H
+
+#include "piconditionvar.h"
+
+
+class PIP_EXPORT PIReadWriteLock {
+public:
+ NO_COPY_CLASS(PIReadWriteLock)
+
+ //! \~english Constructs %PIReadWriteLock.
+ //! \~russian Создает %PIReadWriteLock.
+ PIReadWriteLock();
+
+ //! \~english Destroy %PIReadWriteLock.
+ //! \~russian Деструктор %PIReadWriteLock.
+ ~PIReadWriteLock();
+
+
+ //! \~english Lock for write. If already locked for write or read, than wait until all locks released.
+ //! \~russian Заблокировать на запись. Если уже заблокировано на запись или чтение, то ждёт освобождения блокировок.
+ void lockWrite();
+
+ //! \~english Try to lock for write. Returns if operation was successfull.
+ //! \~russian Пробует заблокировать на запись. Возвращает успех операции.
+ bool tryLockWrite();
+
+ //! \~english Try to lock for write for \"timeout\". Returns if operation was successfull (timeout has not expired).
+ //! \~russian Пробует заблокировать на запись в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
+ bool tryLockWrite(PISystemTime timeout);
+
+ //! \~english Release lock for write.
+ //! \~russian Освобождает блокировку на запись.
+ void unlockWrite();
+
+
+ //! \~english Lock for read. If already locked for write, than wait until write lock released.
+ //! \~russian Заблокировать на чтение. Если уже заблокировано на запись, то ждёт освобождения записывающей блокировки.
+ void lockRead();
+
+ //! \~english Try to lock for read. Returns if operation was successfull.
+ //! \~russian Пробует заблокировать на чтение. Возвращает успех операции.
+ bool tryLockRead();
+
+ //! \~english Try to lock for read for \"timeout\". Returns if operation was successfull (timeout has not expired).
+ //! \~russian Пробует заблокировать на чтение в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
+ bool tryLockRead(PISystemTime timeout);
+
+ //! \~english Release lock for read.
+ //! \~russian Освобождает блокировку на чтение.
+ void unlockRead();
+
+private:
+ int reading = 0;
+ bool writing = false;
+ PIMutex mutex;
+ PIConditionVariable var;
+};
+
+
+class PIP_EXPORT PIReadLocker {
+public:
+ NO_COPY_CLASS(PIReadLocker);
+
+ //! \~english Constructs and lock for read %PIReadWriteLock "l" if "condition" is \c true.
+ //! \~russian Создается и блокирует на чтение %PIReadWriteLock "l" если "condition" \c true.
+ PIReadLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
+ if (cond) rwl.lockRead();
+ }
+
+ //! \~english Release read lock on %PIReadWriteLock if "condition" was \c true.
+ //! \~russian Освобождает блокировку на чтение %PIReadWriteLock если "condition" был \c true.
+ ~PIReadLocker() {
+ if (cond) rwl.unlockRead();
+ }
+
+private:
+ PIReadWriteLock & rwl;
+ bool cond = true;
+};
+
+
+class PIP_EXPORT PIWriteLocker {
+public:
+ NO_COPY_CLASS(PIWriteLocker);
+
+ //! \~english Constructs and lock for write %PIReadWriteLock "l" if "condition" is \c true.
+ //! \~russian Создается и блокирует на запись %PIReadWriteLock "l" если "condition" \c true.
+ PIWriteLocker(PIReadWriteLock & l, bool condition = true): rwl(l), cond(condition) {
+ if (cond) rwl.lockWrite();
+ }
+
+ //! \~english Release write lock on %PIReadWriteLock if "condition" was \c true.
+ //! \~russian Освобождает блокировку на запись %PIReadWriteLock если "condition" был \c true.
+ ~PIWriteLocker() {
+ if (cond) rwl.unlockWrite();
+ }
+
+private:
+ PIReadWriteLock & rwl;
+ bool cond = true;
+};
+
+
+#endif
diff --git a/libs/main/thread/pisemaphore.h b/libs/main/thread/pisemaphore.h
index 5f964408..7bacbecc 100644
--- a/libs/main/thread/pisemaphore.h
+++ b/libs/main/thread/pisemaphore.h
@@ -92,4 +92,4 @@ private:
};
-#endif // PIMUTEX_H
+#endif
diff --git a/libs/main/thread/pithreadmodule.h b/libs/main/thread/pithreadmodule.h
index f5e7c7e3..eba1b509 100644
--- a/libs/main/thread/pithreadmodule.h
+++ b/libs/main/thread/pithreadmodule.h
@@ -56,6 +56,7 @@
#include "pimutex.h"
#include "pipipelinethread.h"
#include "piprotectedvariable.h"
+#include "pireadwritelock.h"
#include "pisemaphore.h"
#include "pispinlock.h"
#include "pithread.h"
diff --git a/main.cpp b/main.cpp
index 34c01013..338791b2 100644
--- a/main.cpp
+++ b/main.cpp
@@ -39,28 +39,66 @@ public:
class RWL {
public:
- void lockWrite() { mutex.lock(); }
- void unlockWrite() { mutex.unlock(); }
- void lockRead() {}
- void unlockRead() {}
+ void lockWrite() {
+ PIMutexLocker _ml(mutex);
+ while (reading > 0 || writing) {
+ var.wait(mutex);
+ }
+ writing = true;
+ }
+ void unlockWrite() {
+ PIMutexLocker _ml(mutex);
+ writing = false;
+ var.notifyAll();
+ }
+ void lockRead() {
+ PIMutexLocker _ml(mutex);
+ while (writing) {
+ var.wait(mutex);
+ }
+ ++reading;
+ }
+ void unlockRead() {
+ PIMutexLocker _ml(mutex);
+ --reading;
+ var.notifyAll();
+ }
+
+private:
+ PIConditionVariable var;
+ int reading = 0;
+ bool writing = false;
PIMutex mutex;
};
PIMutex mutex;
PISemaphore sem(10);
+PIReadWriteLock rwl;
int main(int argc, char * argv[]) {
/*sem.acquire(2);
piCout << sem.tryAcquire(2);
piCout << sem.available();
return 0;*/
- PIThread t_w(
+ PIThread t_w0(
[] {
// PIMutexLocker _ml(mutex);
- piCout << "write start ...";
+ PIWriteLocker rl(rwl);
+ piCout << "write0 start ...";
piMSleep(500);
- sem.release(11);
- piCout << "write end" << sem.available() << "\n";
+ piCout << "write0 end"
+ << "\n";
+ },
+ true,
+ 1_Hz);
+ PIThread t_w1(
+ [] {
+ // PIMutexLocker _ml(mutex);
+ PIWriteLocker rl(rwl);
+ piCout << "write1 start ...";
+ piMSleep(500);
+ piCout << "write1 end"
+ << "\n";
},
true,
1_Hz);
@@ -69,33 +107,36 @@ int main(int argc, char * argv[]) {
PIThread t_r0(
[&cnt0] {
// PIMutexLocker _ml(mutex);
+ PIReadLocker rl(rwl);
piCout << "read0 start ...";
piMSleep(50);
- sem.acquire(2);
- bool ok = true; // sem.tryAcquire(2, 100_ms);
- if (ok) ++cnt0;
- piCout << "read0 end" << sem.available() << ok;
+ // bool ok = rwl.tryLockRead(100_ms);
+ // if (ok) ++cnt0;
+ piCout << "read0 end";
+ // if (ok) rwl.unlockRead();
},
true,
10_Hz);
PIThread t_r1(
[&cnt1] {
// PIMutexLocker _ml(mutex);
+ // PIReadLocker rl(rwl);
piCout << "read1 start ...";
piMSleep(50);
- sem.acquire(2);
- bool ok = true; // sem.tryAcquire(2, 100_ms);
+ bool ok = rwl.tryLockRead(100_ms);
if (ok) ++cnt1;
- piCout << "read1 end" << sem.available() << ok;
+ piCout << "read1 end" << ok;
+ if (ok) rwl.unlockRead();
},
true,
11_Hz);
- piSleep(5.);
+ piSleep(8.);
t_r0.stopAndWait();
t_r1.stopAndWait();
- t_w.stopAndWait();
+ t_w0.stopAndWait();
+ t_w1.stopAndWait();
piCout << cnt0 << cnt1;