/* 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(); }