From 4655d725546b82331a005cdbfd248145a6cb8e39 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 12 Nov 2024 18:50:22 +0300 Subject: [PATCH] new class PISemaphore doc for PIProtectedVariable --- libs/main/thread/piprotectedvariable.h | 21 ++++ libs/main/thread/pisemaphore.cpp | 152 +++++++++++++++++++++++++ libs/main/thread/pisemaphore.h | 95 ++++++++++++++++ libs/main/thread/pithreadmodule.h | 1 + main.cpp | 72 ++++++++++-- 5 files changed, 333 insertions(+), 8 deletions(-) create mode 100644 libs/main/thread/pisemaphore.cpp create mode 100644 libs/main/thread/pisemaphore.h diff --git a/libs/main/thread/piprotectedvariable.h b/libs/main/thread/piprotectedvariable.h index c5bc2b01..b7490f95 100644 --- a/libs/main/thread/piprotectedvariable.h +++ b/libs/main/thread/piprotectedvariable.h @@ -32,24 +32,45 @@ template class PIP_EXPORT PIProtectedVariable { public: + //! \~english Sets value to copy of \"v\" + //! \~russian Устанавливает значение как копию \"v\" void set(const T & v) { PIMutexLocker _ml(mutex); var = v; } + + //! \~english Sets value by moving \"v\" + //! \~russian Устанавливает значение перемещением \"v\" void set(T && v) { PIMutexLocker _ml(mutex); var = std::move(v); } + + //! \~english Returns copy of value + //! \~russian Возвращает копию значения T get() const { PIMutexLocker _ml(mutex); return var; } + + //! \~english Lock mutex and returns reference of value + //! \~russian Блокирует мьютекс и возвращает ссылку на значение T & lock() { mutex.lock(); return var; } + + //! \~english Unlock mutex + //! \~russian Разблокирует мьютекс void unlock() { mutex.unlock(); } + //! \~english Sets value to copy of \"v\" + //! \~russian Устанавливает значение как копию \"v\" + PIProtectedVariable & operator=(const T & v) { + set(v); + return *this; + } + private: mutable PIMutex mutex; diff --git a/libs/main/thread/pisemaphore.cpp b/libs/main/thread/pisemaphore.cpp new file mode 100644 index 00000000..3decf3eb --- /dev/null +++ b/libs/main/thread/pisemaphore.cpp @@ -0,0 +1,152 @@ +/* + PIP - Platform Independent Primitives + PISemaphore, PISemaphoreLocker + 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 PISemaphore pisemaphore.h +//! +//! \~\brief +//! \~english Basic semaphore +//! \~russian Простой семафор +//! +//! +//! \~\details +//! \~english \section PISemaphore_sec0 Synopsis +//! \~russian \section PISemaphore_sec0 Краткий обзор +//! +//! \~english +//! %PISemaphore provides critical code section defence between several threads with resource counting. +//! Semaphore contains logic counter and functions to change it: +//! \a release(), \a acquire() and \a tryAcquire(). +//! +//! For automatic acquire-release use \a PISemaphoreLocker. +//! +//! \~russian +//! %PISemaphore предоставляет межпотоковую защиту критических секций кода с подсчетом ресурсов. +//! Семафор состоит из логического счетчика и методов для его изменения: +//! \a release(), \a acquire() and \a tryAcquire(). +//! +//! Для автоматического захвата-освобождения используйте \a PISemaphoreLocker. +//! +//! \~english \section PISemaphore_sec1 Usage +//! \~russian \section PISemaphore_sec1 Использование +//! +//! \~english +//! +//! \~russian +//! +//! \~\code +//! \endcode +//! \} + + +//! \addtogroup Thread +//! \{ +//! \class PISemaphoreLocker pisemaphore.h +//! +//! \~\brief +//! \~english %PISemaphore autolocker +//! \~russian Автоблокировщик %PISemaphore +//! +//! +//! \~\details +//! +//! \~english +//! When a %PISemaphoreLocker object is created, it attempts to acquire the semaphore resources, if "condition" \c true. +//! When control leaves the scope in which the %PISemaphoreLocker object was created, +//! the %PISemaphoreLocker is destructed and the resources are released, if "condition" was \c true. +//! +//! If "condition" \c false this class do nothing. +//! +//! The %PISemaphoreLocker class is non-copyable. +//! +//! \~russian +//! При создании экземпляра %PISemaphoreLocker захватываются ресурсы семафора, если "condition" \c true. +//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и ресурсы +//! освобождаются, если "condition" был \c true. +//! +//! Если "condition" \c false, то этот объект ничего не делает. +//! +//! Класс %PISemaphoreLocker некопируемый. +//! +//! \~\code +//! // critical section start +//! { +//! PISemaphoreLocker locker(mutex, 5); +//! // ... your code here +//! } +//! // critical section end +//! \endcode +//! \} + + +#include "pisemaphore.h" + + +PISemaphore::PISemaphore(int initial) { + count = initial; +} + + +PISemaphore::~PISemaphore() { + var.notifyAll(); +} + + +void PISemaphore::acquire(int cnt) { + PIMutexLocker _ml(mutex); + while (count < cnt) { + var.wait(mutex); + } + count -= cnt; +} + + +bool PISemaphore::tryAcquire(int cnt) { + PIMutexLocker _ml(mutex); + if (count < cnt) return false; + count -= cnt; + return true; +} + + +bool PISemaphore::tryAcquire(int cnt, PISystemTime timeout) { + PITimeMeasurer tm; + PIMutexLocker _ml(mutex); + while (count < cnt) { + PISystemTime remain = timeout - tm.elapsed(); + if (remain.isNegative()) return false; + var.waitFor(mutex, remain); + } + count -= cnt; + return true; +} + + +void PISemaphore::release(int cnt) { + PIMutexLocker _ml(mutex); + count += cnt; + var.notifyAll(); +} + + +int PISemaphore::available() const { + PIMutexLocker _ml(mutex); + return count; +} diff --git a/libs/main/thread/pisemaphore.h b/libs/main/thread/pisemaphore.h new file mode 100644 index 00000000..5f964408 --- /dev/null +++ b/libs/main/thread/pisemaphore.h @@ -0,0 +1,95 @@ +/*! \file pisemaphore.h + * \ingroup Semaphore + * \~\brief + * \~english Basic semaphore + * \~russian Простой семафор + */ +/* + PIP - Platform Independent Primitives + PISemaphore, PISemaphoreLocker + 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 PISEMAPHORE_H +#define PISEMAPHORE_H + +#include "piconditionvar.h" + + +class PIP_EXPORT PISemaphore { +public: + NO_COPY_CLASS(PISemaphore) + + //! \~english Constructs semaphore with \"initial\" available resources. + //! \~russian Создает семафор с \"initial\" начальными свободными ресурсами. + PISemaphore(int initial = 0); + + //! \~english Destroy semaphore. + //! \~russian Деструктор семафора. + ~PISemaphore(); + + + //! \~english Acquire \"cnt\" resources. If no available resources, than blocks until they freed. + //! \~russian Захватывает \"cnt\" ресурсов. Если свободных ресурсов недостаточно, то блокирует до их появления. + void acquire(int cnt = 1); + + //! \~english Try to acquire \"cnt\" resources. Returns if operation was successfull. + //! \~russian Пробует захватывает \"cnt\" ресурсов. Возвращает успех захвата. + bool tryAcquire(int cnt = 1); + + //! \~english Try to acquire \"cnt\" resources for \"timeout\". Returns if operation was successfull (timeout has not expired). + //! \~russian Пробует захватывает \"cnt\" ресурсов в течении \"timeout\". Возвращает успех захвата (не истек ли тайм-аут). + bool tryAcquire(int cnt, PISystemTime timeout); + + //! \~english Release \"cnt\" resources. + //! \~russian Освобождает \"cnt\" ресурсов. + void release(int cnt = 1); + + //! \~english Returns available resources count. + //! \~russian Возвращает количество свободных ресурсов. + int available() const; + +private: + int count = 0; + mutable PIMutex mutex; + PIConditionVariable var; +}; + + +class PIP_EXPORT PISemaphoreLocker { +public: + NO_COPY_CLASS(PISemaphoreLocker); + + //! \~english Constructs and acquire \"cnt\" resources on semaphore "s" if "condition" is \c true. + //! \~russian Создается и захватывает \"cnt\" ресурсов у семафора "s" если "condition" \c true. + PISemaphoreLocker(PISemaphore & s, int cnt = 1, bool condition = true): sem(s), count(cnt), cond(condition) { + if (cond) sem.acquire(count); + } + + //! \~english Release "cnt" resources on semaphore if "condition" was \c true. + //! \~russian Освобождает "cnt" ресурсов у семафора если "condition" был \c true. + ~PISemaphoreLocker() { + if (cond) sem.release(count); + } + +private: + PISemaphore & sem; + int count = 1; + bool cond = true; +}; + + +#endif // PIMUTEX_H diff --git a/libs/main/thread/pithreadmodule.h b/libs/main/thread/pithreadmodule.h index b9a98069..f5e7c7e3 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 "pisemaphore.h" #include "pispinlock.h" #include "pithread.h" #include "pithreadnotifier.h" diff --git a/main.cpp b/main.cpp index 38593865..34c01013 100644 --- a/main.cpp +++ b/main.cpp @@ -12,8 +12,10 @@ #include "pitranslator_p.h" #include "pivaluetree_conversions.h" -using namespace PICoutManipulators; +#include +using namespace PICoutManipulators; +/* class MyStr: public PIString { public: MyStr(): PIString() {} @@ -32,16 +34,70 @@ public: return *this; } }; +*/ +class RWL { +public: + void lockWrite() { mutex.lock(); } + void unlockWrite() { mutex.unlock(); } + void lockRead() {} + void unlockRead() {} + PIMutex mutex; +}; + +PIMutex mutex; +PISemaphore sem(10); + int main(int argc, char * argv[]) { - PIProtectedVariable var; - // MyStr s("hello"); - var.set("hello"); - auto & v = var.lock(); - // v = "world"; - var.unlock(); - piCout << var.get(); + /*sem.acquire(2); + piCout << sem.tryAcquire(2); + piCout << sem.available(); + return 0;*/ + PIThread t_w( + [] { + // PIMutexLocker _ml(mutex); + piCout << "write start ..."; + piMSleep(500); + sem.release(11); + piCout << "write end" << sem.available() << "\n"; + }, + true, + 1_Hz); + + int cnt0 = 0, cnt1 = 0; + PIThread t_r0( + [&cnt0] { + // PIMutexLocker _ml(mutex); + 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; + }, + true, + 10_Hz); + PIThread t_r1( + [&cnt1] { + // PIMutexLocker _ml(mutex); + piCout << "read1 start ..."; + piMSleep(50); + sem.acquire(2); + bool ok = true; // sem.tryAcquire(2, 100_ms); + if (ok) ++cnt1; + piCout << "read1 end" << sem.available() << ok; + }, + true, + 11_Hz); + + piSleep(5.); + + t_r0.stopAndWait(); + t_r1.stopAndWait(); + t_w.stopAndWait(); + + piCout << cnt0 << cnt1; /*PICodeParser parser; parser.parseFile("client_server.h");