Здравствуйте, Sinclair, Вы писали:
V>>В базе есть механизм семафора, у того счётчик.
V>>Остальные примитивы сигнализации производные.
S>Очень интересно.
Классика.
В основе всего атомарный счётчик.
В общем случае — атомарно изменяемая переменная.
V>>Заявки, блокирующие строки, эквиваленты читателям, а блокирующие всю страницу — писателям.
S>Очень интересно. А read-заявки на строки эквивалентны write-заявкам на строки?
Write-заявки на строки страницы эквиваленты read-заявкам на страницу с т.з. write-заявок на страницу.
Ключевое здесь — уровни параллелизма операций скачут от много к одному и обратно.
S>У нас получилось четыре вида блокировок, кто из них кому эквивалентен?
Да хоть десять.
Я тебе показал отношение одной пары из иерархий блокировок.
Построй сколь угодно глубокую иерархию, согласно прикладной модели.
V>>При появлении писателя семафору ресурса присвается значение счётчика "минус кол-во читателей плюс один".
S>Ага, то есть вы имеете в виду не "настоящий" семафор, а что-то самописаное, так?
Это и есть настоящий.
Тебя же не смущает, что семафор инициализируется произвольным значением своего счётчика?
А так же что в АПИ семафора можно изменять счётчик произвольно?
Или тебе требуется семафор непременно уровня ОС?
Проблемы с таким семафором я упомянул.
Для примера, критическая секция в 90% случаев не дёргает и даже не создаёт семафор уровня ОС, а обходится interlocked-счётчиком, облуживаемым юзер-спейсным кодом.
Рекурсивные критические секции или мьютексы оперируют еще идентификатором потока.
S>Тогда было бы неплохо привести код.
В конце привёл.
V>>Когда последний читатель освободит ресурс, писатель сможет его захватить.
S>Хм. Непонятно вот что: как мы делаем замену значения семафора при "появлении писателя"?
В конце код.
S>Как будет выглядеть освобождение семафора писателем?
В зависимости от состояния очереди.
Если взята схема, где происходит управление очередями, то в этот момент очередь к ресурсу всего одна.
Если схема более "в лоб", то будет прибавление к семафору значения уровня параллелизма.
S>Классический release делает простой инкремент — то есть захватить блокировку сможет не более 1 читателя/писателя.
В Win API:
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
UPD:
В дотнете:
https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.semaphoreslim.release?view=net-5.0#System_Threading_SemaphoreSlim_Release_System_Int32_
https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.semaphore.release?view=net-5.0#System_Threading_Semaphore_Release_System_Int32_
S>Если мы сделаем опять инкремент на "большое значение", а в очереди несколько писателей, то может произойти совместный захват.
Очередь писателей одна.
Если эту очередь мы не обслуживаем явно, т.е. разводим хаос в потоках, тогда придётся сериализовать их через еще один семафор.
Собсно, "классическая" реализация RO-RW блокировки так и делается, но у неё есть серьёзные бока, о которых я упоминал.
V>>Одно но — на многопроцессорной машине в режиме вытесняющей многозадачности наших "очередей" нет, есть очереди уровня ОС, поэтому возможно голодание писателей, т.к. даже при ограничении доступа к ресурсу счётчиком 1, его могут захватить конкурентные потоки-читатели.
V>>Решается это либо системой управляемых приложением очередей, либо доп.механизмом на семафоре со счётчиком 1 — на т.н. турникете.
S>Отлично.
Не, "турникет" из классической реализации — зло.
S>То есть у нас уже как минимум самописанный семафор (поверх какого-то механизма синхронизации ОС) +турникет.
"Самописный" семафор имеет смысл в самописной же системе очередей заявок (задач).
Иначе будет хаос в потоках.
Собсно, даже task-like фреймворки, типа дотнетного, изкаробки не спасают, бо task stealing алгоритм такой же тупой.
Т.е. не владеет прикладной информацией.
Но дотнет даёт возможность написать собственный шедуллер тасков, и тогда можно будет наводить порядок согласно прикладной семантики.
S>Ну, либо очередь, управляемая приложением, что вообще множит всю идею единственного семафора на ноль.
Офигенные рассуждения. ))
Ты опять меня удивляешь...
Я ХЗ уже как возвращать тебя снова и снова на грешную землю.
Мне не нравится твой тон, твои предположения, твои рассуждения в целом, бо они попахивают запретом на мозговую деятельность как таковую.
В двух словах — целью разработки обычно является решение поставленных задач.
Если одной из задач является разруливание сложных/глубоких иерархий блокировок, то целевой разрабатываемый код и должен решать именно эту задачу (если эта задача уже не решена "фреймвороком", библиотеками и т.д., но тогда бы и задача, собсно, не стояла).
Т.е., забавно следует из твоего тона, что задачу управления доступом к ресурсам ты решил выделить в некий особый класс задач, которые разработчик не имеет права решать, не имеет даже права рассуждать о способах решения таких задач. ))
С другой стороны, это где-то перекликается с тем, как ты рассуждаешь о малоинтересных мне баззвордах, даже имеешь наглость пытаться подловить оппонента в невладении некоторыми баззвордами, при том что отказываешь себе и окружающим в понимании механизмов, лежащих за этими баззвордами.
ИМХО, разработчика разумного должно интересовать понимание механизмов, а не их имена собственные, розданные частными фирмами для подсистем своих поделий.
Тем более, что там всегда более-менее примитивно, не сложнее даваемого на 3-м курсе профильных специальностей.
S>Давайте добавим в смесь update блокировки. Как вы реализуете их на одном семафоре, вместе с shared и exclusive?
Откуда ты взял "на одном"?
Абстракция семафора — это примитив самого нижнего уровня, самый простой кирпичик.
V>>Т.е., система прикладных очередей предпочтительней в случае сложных иерархических блокировок, реализцется, например, через асинхронщину или "зеленые потоки", когда мы сами управляем нагрузкой, бо лишние примитивы сигнализации всегда дороги, да еще потенциально вносят помехи в системах с вытесняющей многозадачностью — например, поток читателя должен пройти через турникет, т.е. дёрнуть примитив сигнализации дважды, но поток может быть вытеснен после первой фазы прохода через турникет и тогда этот поток затормозит всех — и читателей и писателей.
S>Вижу, вы начинаете понимать сложности реализации разделения ресурсов в СУБД.
И как мне отвечать на эту очередную твою тупизну?
Вот где ты увидел сложности?
Если тебе это сложно — смени род деятельности, какие проблемы?
Я тебе как ребенку расписал на пальцах аж пару решений простейшего алгоритма.
При этом не просто так указал на недостаток "классического" — как на факт голодания писателей, так и на ненадёжность классического решения проблемы голодания через турникет.
И вместо этого дал более простой и лишенный таких недостатков алгоритм.
Т.е. тебе уже всё разжевали, а ты проглотить не в состоянии, "сложности" у него.
Синклер, это уже зашквар, и ты мне в этой теме уже 3-й раз поднадоел.
Уже не для тебя пишу, а чтобы подобным тебе стало стыдно, за поверхностность, увлечение баззвордами и привычкой оперировать докой не глубже уровня "руководства пользователя".
V>>В общем, при организации сложных иерархий доступа к ресурсам рулит кооперативная многозадачность.
V>>В этом смысле планировщики ОС тупые. ))
V>>Не потому что алгоритмы планировщика тупые, а потому что эти алгоритмы не обладают информацией о происходящем на прикладном уровне.
S>Ок, давайте рассмотрим организацию сложных иерархий доступа к ресурсам.
Уже всё давно рассмотрено.
Без явных управлений очередями заявок системы с глубокими иерархиями блокировок не живут, т.е. полагаться на то, что шедуллер ОС "сам вывезет" — глупо.
Не вывезет.
Поэтому, их так и не пишут, ес-но.
При том что расписать сколь угодно сложные сценарии на очередях и семафорах — как двумя пальцами об асфальт.
Так зачем жрать кактус, да еще принуждать к этому окружающих, рассуждая в духе "ааа, ну это самописные семафоры, нещитово"?
Сломанная какая-то логика.
Плюс сверкание невладением даже азами — ты ведь был не в курсе, как управляют заявками в сложных СМО, в своих эти рассуждениях про "самописные семафоры".
А как он может быть несамописный, когда порой привязан к строке, а строки не всегда влазят в оперативку, да и вообще кол-во системных хендлов заведомо ограничено? ))
Да и дороги они, эти системные хендлы.
V>>В системе с явными очередями читатели поступают из многих очередей (столько очередей, какова конкурентность системы), а писатели поступают из одной.
V>>При появлении первого писателя все вновь поступающие читатели ставятся в очередь писателей (либо эти очереди просто "перекрываются").
V>>При появлении из той очереди первого читателя они опять раскидываются по очередям читателей до появления первого писателя (либо очереди читателей опять открываются) и т.д.по кругу.
V>>Простой и элегантный алгоритм, рекомендую.
S>Непонятно описываете.
Медитируй, там всё понятно.
V>>Этим же алгоритмом точно так же элегантно обслужишь отношение блокировок уровня строки и страницы.
S>Это как это так? Я тупой, не понимаю, как устроен примитивы "захватить shared row lock", "отпустить shared row lock", "захватить exclusive row lock", "отпустить exclusive row lock" в такой системе.
Жаль.
S>Что такое "очереди перекрываются"?
Перестают обслуживаться.
S>Как добавить в этот простой и элегантный алгоритм update lock?
Пусть будет домашнее задание.
Я и так слишком подробно всё описал.
А твои вопросы вызваны тем, что ты еще не уделил этой простой схеме ни минуты.
Нарисуй очереди, ресурс, стрелки, писателей-читателей, протрассируй работу, и всё станет понятно.
Например, студентам понятно.
S>И тем более я не понимаю, как одним и тем же алгоритмом мы будем обрабатывать ещё и shared page lock и exclusive page lock.
Мда...
V>>И да, небольшой хинт — при попытках расписывать происходящее на семафорах не имеет смысла думать семафорами уровня ОС, где очереди к семафорам "даны сверху", а сами ОС реализуют выталкивающую многозадачность.
S>Да, семафорами уровня ОС это просто невозможно сделать.
Разумеется, возможно.
Но система будет далека от оптимальной.
По причинам, которые я уже упоминал в прошлом и этом сообщении.
S>Ну, например, просто потому, что нет метода "заменить текущее значение семафора на -x"
Есть, соотв. сигнатуру ВинАПИ дал выше.
Защити код обращения к семафору критической секцией и это можно будет промоделировать на семафорах уровня ОС.
Еще небольшой хинт — т.к. обращение к АПИ ОС относительно дорогое само по себе, даже не беря во внимание потенциальные проблемы из-за хаотичного (с т.з. пркладного кода) шедуллинга, есть классический вариант "облегченного семафора", что-то типа такого:
class LightweightSemaphore : boost::noncopyable
{
public:
explicit LightweightSemaphore(size_t initialCount)
: counter_(ssize_t(initialCount))
, sema_(0)
{}
// it safe only without timeout
void acquire() {
if(Interlocked::decrement(&counter_) >= 0)
return;
sema_.acquire();
}
bool tryAcquire() {
while(true) {
const ssize_t counter = counter_;
if(counter <= 0)
return false;
if(Interlocked::cas(&counter_, counter - 1, counter))
return true;
Interlocked::pause();
}
}
void release() {
if(Interlocked::increment(&counter_) < 1)
sema_.release();
}
private:
ssize_t volatile counter_;
OnixS::Concurrency::Semaphore sema_;
};
В кишках дотнета, да и в других проектах аналоги сверкают регулярно.
V>>Представь, что у тебя есть просто модель счётчика, управлять которым ты можешь атомарно.
V>>Если не охота возиться с зелеными потоками, то в моделирующей программе это можно сделать, например, через цикл CAS:
V>>V>>while(!CAS(&sema_counter, new_value, old_Value)) {
V>> asm ("pause");
V>> old_value = sema_counter;
V>> new_Value = calc_new_value(oldValue);
V>>}
V>>
S>Ну, вот пока что в голове полная схема не выстраивается. Ни с семафором, ни с очередями.
Уверен, ты пока не пробовал.
Попробовал бы — не писал бы того, что писал.
Пока что ты демонстрируешь неприкрытый эдакий протест против того, чтобы кто-то вообще эти вопросы кишками наружу выворачивал.
Бо иначе как тебе в следующий раз говорить с придыханием о своей любимой эзотерике, доступной лишь посвящённым?
Это ж пол-жизни, считай, коту под хвост, бо король, как обычно, оказался голым. ))