Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Потоки и общие данные  [new]
sergq
Member

Откуда:
Сообщений: 661
Здравствуйте

Раньше не работал с потоками и общими данными. Голова квадратная, по этому могу тупить.

Упрощенно. Допустим есть некий буфер. Размером килобайт. В начале его примерно такая структура.

theader = record
LockFlag: byte;
ReaderCount: integer;
End

Последняя переменная—счетчик читателей. Исходя из того, что писать в буфер можно при наличии нуля читателей.

Как я вижу работу потоков с такого рода буфером. С критическими секциями.

Допустим изначально флаг блокировки none. Ну вернее флаг текущей выполняемой операции с блоком.

Первый поток хочет читать. В критической секции проверяет флаг блокировки. Если none или blockread, то открываем критическую секцию, ставим флаг блокировки в blockread, увеличиваем счетчик читателей и выходим из критической секции. Далее читаем—зачитываемся. По окончании чтения опять открываем критическую секцию, уменьшаем количество читателей и если получилось ноль— ставим блокировку none. Иначе оставляем блокировку на чтение.И завершаем критическую секцию.

А если хотим писать туда, то при отсутствии блокировки ставим блокировку типа blockwrite. Выходим из критической, пишем. Потом опять в критической сбрасываем блокировку в none.

Пока у буфера блокировка типа blockread и readercounter не равен нулю ставить блокировку на запись не можем. Те если поток хочет осуществить запись он должен подождать , пока блокировка будет none. Единственный вопрос— а как подождать? И соответственно желающие записать должны подождать, пока блокировка не станет none. Но как? Простым циклом while? Подозреваю, что не прокатит

Мысль вроде в правильном направлении, но не уверен, тк ни разу с потоками и разделяемыми буферами не работал
9 апр 19, 23:54    [21857800]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
sergq
Единственный вопрос— а как подождать?
Самый простой и скорее всего лучший вариант - выкинуть все эти флаги и счетчики, а все действия с буфером производить внутри "открытой" критической секции, и тогда всё будет работать само.
10 апр 19, 00:07    [21857811]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
sergq
Member

Откуда:
Сообщений: 661
YuRock
sergq
Единственный вопрос— а как подождать?
Самый простой и скорее всего лучший вариант - выкинуть все эти флаги и счетчики, а все действия с буфером производить внутри "открытой" критической секции, и тогда всё будет работать само.


И об этом думал) собственно да, читателей может быть много. И они двумя критическими секциями ставятт—снимают флаги и счетчики.

А ждать то для блокировки на запись вроде как надо. Ибо допустим есть 20 читателей. И тут вдруг нарисовался писатель. А он может писать только тогда, когда readercount равен нулю. Те в любом случае ему надо как то ждать, когда отвалятся все 20 читателей
10 апр 19, 00:14    [21857816]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
asviridenkov
Member

Откуда:
Сообщений: 3948
sergq,

http://edn.embarcadero.com/article/28258
10 апр 19, 00:19    [21857819]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

sergq
писать в буфер можно при наличии нуля читателей.

А если нужен тебе RWLock, так и используй его. Он в VCL уже готовый есть.

Но я бы ещё поразмыслил над задачей. Может, для пущей производительности, Copy-on-Write
там будет в жилу.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 00:25    [21857821]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
sergq
Member

Откуда:
Сообщений: 661
Dimitry Sibiryakov
sergq
писать в буфер можно при наличии нуля читателей.

А если нужен тебе RWLock, так и используй его. Он в VCL уже готовый есть.

Но я бы ещё поразмыслил над задачей. Может, для пущей производительности, Copy-on-Write
там будет в жилу.


Да вроде как я и описал RWlock. Только не осилил задачу ожидания возможности записи. Хочется все ж без vcl, самому) мозги поформировать. А то последнее время разжижаются

copy-on-write это когда при необходимости записи мы делаем копию буфера, модифицируем и помещаем обратно? Чет не пойму зачем так делать? Все равно ж в итоге придется вернуть модифицированные данные на место. А для этого как раз и придется ставить лок при записи обратно. Чтоб читатели не ломанулись читать недописанные данные
10 апр 19, 01:02    [21857831]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

sergq
Хочется все ж без vcl, самому) мозги поформировать. А то последнее время
разжижаются

Тогда тебе к Рихтеру, там расписаны эти примитивы. Одним мутексом не обойдёшься, надо два.

sergq
copy-on-write это когда при необходимости записи мы делаем копию буфера, модифицируем и
помещаем обратно? Чет не пойму зачем так делать? Все равно ж в итоге придется вернуть
модифицированные данные на место. А для этого как раз и придется ставить лок при записи
обратно. Чтоб читатели не ломанулись читать недописанные данные

"Запись обратно" это атомарная операция присваивания одного указателя, в локе не
нуждается. Старые читатели читают старый буфер, новые читатели читают уже новый. Старый
освобождается при падении его счётчика ссылок до нуля.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 01:10    [21857832]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
sergq
Member

Откуда:
Сообщений: 661
Dimitry Sibiryakov
sergq
Хочется все ж без vcl, самому) мозги поформировать. А то последнее время
разжижаются

Тогда тебе к Рихтеру, там расписаны эти примитивы. Одним мутексом не обойдёшься, надо два.

sergq
copy-on-write это когда при необходимости записи мы делаем копию буфера, модифицируем и
помещаем обратно? Чет не пойму зачем так делать? Все равно ж в итоге придется вернуть
модифицированные данные на место. А для этого как раз и придется ставить лок при записи
обратно. Чтоб читатели не ломанулись читать недописанные данные

"Запись обратно" это атомарная операция присваивания одного указателя, в локе не
нуждается. Старые читатели читают старый буфер, новые читатели читают уже новый. Старый
освобождается при падении его счётчика ссылок до нуля.


Нездоровое желание читать и писать в один и тот же участок памяти)

Можно ж теоретически через мьютекс подождать? Первый читатель со создаст мьютекс. Последний освободит. А писатель будет ждать освобождения?

И кстати почему запись обратно не нуждается в локе? Операция присваивания то тоже не атомарна? Тк все ж состоит из несколько асм комманд? Только через interlocked функции. А это тоже своего рода лок. Где то тут даже вы про это писали.
10 апр 19, 01:18    [21857835]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

sergq
Операция присваивания то тоже не атомарна? Тк все ж состоит из несколько асм комманд?
Только через interlocked функции. А это тоже своего рода лок.

interlocked функции, конечно, лок, но такой короткий, что на производительности
практически не сказывается. И при желании можно обойтись и без них, поскольку на
интеловской архитектуре для данных до размера указателя нет thorn reads, простое
присваивание и чтение атомарны, это одна asm команда.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 12:38    [21858178]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
Dimitry Sibiryakov
простое
присваивание и чтение атомарны, это одна asm команда

Только простое присваивание и чтение.
А еще всё это так в рамках одного процессора (ядра).
10 апр 19, 12:58    [21858206]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
YuRock
А еще всё это так в рамках одного процессора (ядра).
В смысле, что может произойти одновременное выполнение этой одной asm-команды несколькими процессорами.
10 апр 19, 13:01    [21858210]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

YuRock
Только простое присваивание и чтение.

Только о них я и говорю.

YuRock
В смысле, что может произойти одновременное выполнение этой одной asm-команды несколькими
процессорами.

Может, но память-то у них всё равно общая, так что один процессор не сможет прочитать
смесь из двух разных значений, записываемых остальными. То есть если в памяти лежит
12345678, а один процессор пишет 87654321, то второй никогда не получит 12344321 или
87655678. По крайней мере именно так я читаю спеки.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 13:06    [21858221]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimonka
Member

Откуда:
Сообщений: 1178
Есть ещё стандартный TMultiReadExclusiveWriteSynchronizer и его альтернативы:
https://stackoverflow.com/questions/10378253/faster-tmultireadexclusivewritesynchronizer
10 апр 19, 13:17    [21858239]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

Dimitry Sibiryakov
один процессор не сможет прочитать смесь из двух разных значений, записываемых остальными.

Хотя, конечно, это только для очень узкого класса задач. COW так не организуешь: пока ты
прочитал старый указатель и пытаешься увеличить счётчик ссылок, кто-то другой его уже
довёл до нуля, память освободил и ты получаешь AV.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 13:21    [21858245]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Valery_B
Member

Откуда: Москва
Сообщений: 1976
sergq
Мысль вроде в правильном направлении, но не уверен, тк ни разу с потоками и разделяемыми буферами не работал

У тебя не правильный подход.
Для чтения - не нужны блокировки и критические секции.
Как правильно сделать чтение/запись из общих данных написано в шаблоне проектирования Блокировка с двойной проверкой

Краткий смысл:
1. Прежде чем прочитать, спрашиваем - А есть ли то, что нужно прочитать?
2. Если есть - читаем. В общем-то и всё.
3. Если нет, входим в крит. секцию.
4. После входа - проверяем повторно А есть ли то, что нужно прочитать?, т.к. во время входа туда мог положить это другой поток.
5. Если данные есть - читаем. При необходимости - кладём их. Выходим из критической секции.
10 апр 19, 13:59    [21858298]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
Dimitry Sibiryakov
YuRock
Только простое присваивание и чтение.

Только о них я и говорю.

YuRock
В смысле, что может произойти одновременное выполнение этой одной asm-команды несколькими
процессорами.

Может, но память-то у них всё равно общая, так что один процессор не сможет прочитать
смесь из двух разных значений, записываемых остальными. То есть если в памяти лежит
12345678, а один процессор пишет 87654321, то второй никогда не получит 12344321 или
87655678. По крайней мере именно так я читаю спеки.

Это всё понятно. Только когда, скажем, 8 процессоров одновременно захотят увеличить данные, находящиеся в ячейке памяти, на единицу, то в результате мы можем получить, что это значение увеличилось на [от 1 до 8 как повезет]. Хотя и запись, и чтение - атомарные операции, но толку от этого будет мало.
10 апр 19, 15:38    [21858449]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1579
YuRock,

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

https://habr.com/ru/post/196548/
10 апр 19, 16:02    [21858501]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48418

YuRock
8 процессоров одновременно захотят увеличить данные

А, так "увеличить" это совсем другая операция, я про неё не говорил.

Posted via ActualForum NNTP Server 1.5

10 апр 19, 16:35    [21858582]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
X-Cite
Они будут синхронизированы между собой
Если это сделать.
10 апр 19, 17:53    [21858654]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4010
Dimitry Sibiryakov
YuRock
8 процессоров одновременно захотят увеличить данные

А, так "увеличить" это совсем другая операция, я про неё не говорил.
Да, не говорил. Но просто что-то прочитать и просто что-то записать - обычно, этого мало для построения логики программ :)
А малейшее усложнение уже ведет к необходимости синхронизации группы команд.
10 апр 19, 17:55    [21858656]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Barlone
Member

Откуда:
Сообщений: 1329
Dimitry Sibiryakov
Dimitry Sibiryakov
один процессор не сможет прочитать смесь из двух разных значений, записываемых остальными.

Хотя, конечно, это только для очень узкого класса задач. COW так не организуешь: пока ты
прочитал старый указатель и пытаешься увеличить счётчик ссылок, кто-то другой его уже
довёл до нуля, память освободил и ты получаешь AV.
Да, ну очень узкого. Даже классика - Алгоритм Деккера на современных процессорах просто так без барьеров памяти не будет работать корректно.
10 апр 19, 18:13    [21858667]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5213
sergq
Да вроде как я и описал RWlock. Только не осилил задачу ожидания возможности записи. Хочется все ж без vcl, самому) мозги поформировать. А то последнее время разжижаются

самый примитивный и рабочий вариант- тынц
единственное практически у всех алгоритмов нельзя с readlock-a войти во writelock
11 апр 19, 09:55    [21858975]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5213
Dimitry Sibiryakov
Может, но память-то у них всё равно общая, так что один процессор не сможет прочитать
смесь из двух разных значений, записываемых остальными. То есть если в памяти лежит
12345678, а один процессор пишет 87654321, то второй никогда не получит 12344321 или
87655678. По крайней мере именно так я читаю спеки.
всё это работает когда данные выровнены + не превышают 32-бит, с границами блоков всё уже не так просто, байты могут быть вообще в разных физических планках памяти

Dimitry Sibiryakov
interlocked функции, конечно, лок, но такой короткий, что на производительности
практически не сказывается.
они заставляют конкурирующий проц сбрасывать кэш

для теста достаточно запустить несколько потоков только и делающих что изменяющих один Int, если это будет делать только один поток, то это будет раз в 5 быстрее, чем если бы это делали несколько, но это конечно такой критический вариант теста
11 апр 19, 10:06    [21858982]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
Bred eFeM
Member

Откуда:
Сообщений: 527
sergq,
+
TSRWSynLock = record
private
 nRd, nWr    :Integer;
 class procedure Sleep_; static;
 // class var fSleepCount : NativeInt;
 class var fNoSleepInWait :Boolean;
public
 class property NoSleepInWait : Boolean read fNoSleepInWait write fNoSleepInWait;
public
 procedure RdEnter;
 procedure WrEnter;
 procedure RdLeave; inline;
 procedure WrLeave; inline;
end;

procedure TSRWSynLock.RdEnter;
begin
 while True do
  begin
   AtomicIncrement(nRd);
   if (nWr = 0)
    then Break;

   AtomicDecrement(nRd);
   Sleep_;
  end;
end;

procedure TSRWSynLock.WrEnter;
begin
 while True do
  begin
   if ( AtomicExchange(nWr, 1) = 1 )
    then Sleep_
   else
    begin
     while (nRd <> 0) do Sleep_;
     Break;
    end;
  end;
end;

procedure TSRWSynLock.RdLeave;
begin
 AtomicDecrement(nRd);
end;

class procedure TSRWSynLock.Sleep_;
begin
 // AtomicIncrement(fSleepCount);
 if ( fNoSleepInWait )
  then YieldProcessor()
   else if ( not SwitchToThread() )
    then Sleep(1);
end;

procedure TSRWSynLock.WrLeave;
begin
 AtomicDecrement(nWr);
end;
11 апр 19, 16:19    [21859673]     Ответить | Цитировать Сообщить модератору
 Re: Потоки и общие данные  [new]
sergq
Member

Откуда:
Сообщений: 661
Бум осмысливать всю информацию)


Возник такой вопрос. По логике блокировок. Допустим применительно к базам данных.

Допустим есть операция вставки. В моем понимании она происходит так. Может слегка упрощенно.
1. Поиск последней pointer page
2. На ней поиск свободного слота.
3. По номеру из слота взять data page
4. Найти на ней свободный слот для данных.
5. Записать инфу , что очередной слот занят.
6. Записать сами данные

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

Как в таких случаях блокировки расставляются?
Как вариант.
Блокируется PP, найденная на первом шаге для всех операций, кроме выборки. И так же с DP. И вся эта связка разблокируется только после того, как все последовательность операций выполнится?
14 апр 19, 16:17    [21861614]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить