Как реализовать рекурсивную блокировку MRSW?

Я нашел простой способ сделать это... У меня была chroot'ed копия живой файловой системы CD (От squashfs) и при помощи повсеместности в поддельном корне, я установил на других целевых системах. Кроме того, короткий сценарий оболочки помогает автоматизировать ввод поддельного корня и рабочей повсеместности. Главное избежать случайно перезаписывает Вашу старую установку на внешнем жестком диске.

6
задан fnawothnig 31 August 2009 в 09:53
поделиться

3 ответа

Хорошо, я решил это.

Это можно сделать с помощью всего 2 семафоров, критической секции и почти не большей блокировки, чем для обычной нерекурсивной блокировки MRSW (очевидно, что некоторые больше процессорного времени, затрачиваемого на блокировку, потому что этим мультиотображением нужно управлять) - но это сложно . Структура, которую я придумал, выглядит так:


// Protects everything that follows, except mWriterThreadId and mRecursiveUpgrade
CRITICAL_SECTION mLock;
// Semaphore to wait on for a read lock
HANDLE mSemaReader;
// Semaphore to wait on for a write lock
HANDLE mSemaWriter;
// Number of threads waiting for a write lock.
int mWriterWaiting;
// Number of times the writer entered the write lock.
int mWriterActive;
// Number of threads inside a read lock. Note that this does not include
// recursive read locks.
int mReaderActiveThreads;
// Whether or not the current writer obtained the lock by a recursive 
// upgrade. Note that this member might be set outside the critical
// section, so it should only be read from by the writer during his
// unlock.
bool mRecursiveUpgrade;
// This member contains the current thread id once for each
// (recursive) read lock held by the current thread in addition to an 
// undefined number of other thread ids which may or may not hold a 
// read lock, even inside the critical section (!).
std::multiset<unsigned long> mReaderActive;
// If there is no writer this member contains 0.
// If the current thread is the writer this member contains his
// thread-id.
// Otherwise it can contain either of them, even inside the 
// critical section (!).
// Also note that it might be set outside the critical section.
unsigned long mWriterThreadId;

Теперь основная идея такова:

Полное обновление mWriterWaiting и mWriterActive для разблокировки выполняется путем разблокировки нить.

Для mWriterThreadId и mReaderActive это невозможно, поскольку ожидающий поток должен вставить себя, когда он был освобожден.

Итак, правило:

3
ответ дан 17 December 2019 в 18:18
поделиться

Ну, я немного подумал. Начиная с простого «два семафора и критическая секция», в структуру добавляется счетчик блокировок записи и TID записи-владельца.

Разблокировка по-прежнему устанавливает большую часть нового статуса в crissec. Читатели по-прежнему обычно увеличивают счетчик блокировок - рекурсивная блокировка просто добавляет несуществующего считывающего устройства к счетчику.

Во время записи lock () я сравниваю TID владельца, и если писатель уже владеет им, счетчик блокировки записи увеличивается.

1281] Установка нового идентификатора записи TID не может быть выполнена с помощью unlock () - она ​​не знает, какой из них будет разбужен, но если писатели сбрасывают его обратно на ноль в их unlock (), это не проблема - текущий поток id никогда не будет равен нулю, и его установка является атомарной операцией.

Все звучит достаточно просто - осталась одна неприятная проблема: Рекурсивная блокировка читателя-читателя, пока писатель ожидает, зайдет в тупик. И я не знаю, как решить эту проблему, связанную с блокировкой, ориентированной на читателя ... каким-то образом мне нужно знать, есть ли у меня уже блокировка считывателя.

Использование TLS звучит не слишком хорошо после того, как я понял что количество доступных слотов может быть довольно ограниченным ...

0
ответ дан 17 December 2019 в 18:18
поделиться

Насколько я понимаю, вам необходимо предоставить вашему автору записи эксклюзивный доступ к данным, в то время как считыватели могут работать одновременно (если это не то, что вам нужно, поясните, пожалуйста, свой вопрос).

Я думаю, вам нужно реализовать своего рода «обратный семафор», то есть семафор, который будет блокировать поток, когда он положителен, и сигнализировать всем ожидающим потокам, когда он равен нулю. Если вы сделаете это, вы можете использовать в своей программе два таких семафора. Тогда работа ваших потоков может быть следующей:

Reader:
(1) wait on sem A
(2) increase sem B
(3) read operation
(4) decrease sem B

Writer:
(1) increase sem A 
(2) wait on sem B
(3) write operation
(4) decrease sem A

Таким образом, писатель выполнит операцию записи, как только все ожидающие считывания закончат чтение. Как только ваш писатель закончит, читатели могут возобновить свою работу, не блокируя друг друга.

Я не знаком со средствами мьютексов / семафоров Windows, но я могу придумать способ реализации таких семафоров с использованием API потоков POSIX (объединение мьютекса, счетчика и условной переменной).

0
ответ дан 17 December 2019 в 18:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: