Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
На просторах интернета встретилось несколько реализаций на Delphi. И даже на любимом sql.ru. Но все они показались мне замороченные и если честно очень длинные, хотя возможно и быстрые.
У меня же задача простая. Есть 1 поток писатель и 1 поток читатель. Буфер создается заранее и заполняется массивами TidBytes.
Если писатель быстрее читателя или наоборот, то ждем.
Так как я еще тот синхронизатор/оптимизатор, то подскажите свежим взглядом, где могут быть ошибки чтения/записи в буфер?

TLockFreeQueue = class
    private
      FHead: Int64;
      FTail: Int64;
      FSize: int64;
      FItems: array of TPacket;
    public
      function PushObject(AData: TidBytes; ASize: integer): boolean;
      function PopObject(): TPacket;
      constructor Create(const ASize: integer);
      destructor Destroy(); override;
    end;

constructor TLockFreeQueue.Create(const ASize: integer);
var
  i: integer;
begin
  FHead:= 0; //заполняет писатель
  FTail:= 0; //заполняет читатель
  FSize:= ASize;
  SetLength(FItems, ASize);
  for i := Low(FItems) to High(FItems) do
  FItems[i]:= TPacket.Create(UDP_PACKET_SIZE);
end;

destructor TLockFreeQueue.Destroy;
var
  i: integer;
begin
  try
    for i := Low(FItems) to High(FItems) do
    FItems[i].Free;
    FItems:= nil;
  finally
    inherited;
  end;
end;

function TLockFreeQueue.PushObject(AData: TidBytes; ASize: integer): boolean;
var
  Next: integer;
begin

  Next:= TInterlocked.Read(FHead)+1;

  if Next >= FSize then Next:= 0;

  if Next = TInterlocked.Read(FTail) then
  begin
    Result:= False;
    Exit;
  end;

  CopyTIdBytes(AData, 0, FItems[FHead].PackUDP, 0, ASize);
  FItems[FHead].Size:= ASize;

  TInterlocked.Exchange(FHead, Next);
  Result:= True;
end;

function TLockFreeQueue.PopObject(): TPacket;
var
  Next: integer;
begin

  if (TInterlocked.Read(FHead) = TInterlocked.Read(FTail)) then begin
    Result := nil;
    Exit;
  end;

  Next:= TInterlocked.Read(FTail)+1;

  if Next >= FSize then
  Next:= 0;

  Result:= FItems[FTail];
  TInterlocked.Exchange(FTail, Next);
end;
14 фев 20, 18:48    [22080307]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1634
Вашу проблему решает уже готовый

http://docwiki.embarcadero.com/Libraries/Rio/en/System.Generics.Collections.TThreadedQueue

при этом он решает еще и задачу несколько читают, несколько пишут.
14 фев 20, 18:58    [22080313]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
все так. так и использую на текущий момент. Но скорости не хватает. В целом архитектура такая: Один писатель и куча читателей.
Для каждого читателя отдельная очередь с писателем. И такое чувство, что читатели через крит. секции притормаживают писателя, а мне это совсем не нравиться
14 фев 20, 19:18    [22080328]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11498
X-Cite
Вашу проблему решает уже готовый
http://docwiki.embarcadero.com/Libraries/Rio/en/System.Generics.Collections.TThreadedQueue
при этом он решает еще и задачу несколько читают, несколько пишут.
Только там до Токио включительно, был баг в методе Grow
14 фев 20, 19:26    [22080333]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11498
cptngrb
где могут быть ошибки чтения/записи в буфер?
При наличии более одного читателя или писателя ошибки гарантированы

TInterlocked.Exchange для одного читателя/писателя не имеет смысла, для нескольких смотри выше

TInterlocked.Read вообще бессмысленен.
14 фев 20, 19:43    [22080346]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1634
cptngrb
все так. так и использую на текущий момент. Но скорости не хватает. В целом архитектура такая: Один писатель и куча читателей.
Для каждого читателя отдельная очередь с писателем. И такое чувство, что читатели через крит. секции притормаживают писателя, а мне это совсем не нравиться

Монитор написан так, что если вы бесконечно пишете и читаете то критическая секция никогда не сработает. Там первые вроде 50 циклов/тактов проверка на ожидание как раз фрилоковая, а потом чтобы не нагружать процессор уже блокировка.
14 фев 20, 19:43    [22080347]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
X-Cite,бесконечно пишете и читаете то критическая секция никогда не сработает. В смысле? А как же синхронизация?
14 фев 20, 19:51    [22080350]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
Вопрос не совсем по теме. А никто не знает какая пропускная способность сокета UDP?
14 фев 20, 19:53    [22080351]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
Dimitry Sibiryakov
Member

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

cptngrb
В целом архитектура такая: Один писатель и куча читателей.
Для каждого читателя отдельная очередь с писателем. И такое чувство, что читатели через
крит. секции притормаживают писателя

Это для UDP? Какая-то вывернутая наизнанку архитектура. Обычно бывает наоборот: один поток
только и делает что читает из сокета, а все остальные в него пишут, даже не
синхронизируясь, ибо blocking mode.

Posted via ActualForum NNTP Server 1.5

14 фев 20, 19:56    [22080353]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
Dimitry Sibiryakov, мне нужно читать только. Я одним потоком считываю с сокета данные и передаю в другие, которые уже собирают из пакетов конфетку
14 фев 20, 20:17    [22080361]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
просто я называю поток, который читает из сокета ПИСАТЕЛЕМ своего буфера
14 фев 20, 20:18    [22080362]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
Dimitry Sibiryakov
Member

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

Тогда lock-free алгоритмы тебе не только не нужны, но и полностью противопоказаны,
поскольку приводят к процессорному голоданию producer-а.

Posted via ActualForum NNTP Server 1.5

14 фев 20, 21:06    [22080372]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
Bred eFeM
Member

Откуда:
Сообщений: 535
cptngrb,
Для каждого читателя отдельная очередь с писателем.
для синхры достаточно одного boolean без interlock
И такое чувство, что читатели через крит. секции притормаживают писателя
ну,
Если писатель быстрее читателя или наоборот, то ждем.
и как ты ждёшь?
(если ждёшь, то это уже не Lock-free)



И такое чувство
сделай чтобы это было не чувство, а реальные цифры



Я одним потоком считываю с сокета данные и передаю в другие, которые уже собирают из пакетов конфетку
Если цена передачи данных между потоками соизмерима со сбором конфетки, то можно ускориться в разы используя пул потоков считывателей из сокета (например, IOCP) внутри которых и будет обработка.

Сообщение было отредактировано: 15 фев 20, 15:13
15 фев 20, 15:06    [22080498]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
cptngrb
Member

Откуда:
Сообщений: 518
[quot Bred eFeM#22080498]
и как ты ждёшь?

В первом посте вроде понятно. Кто быстрее тот и ждет.

IOCP надо попробовать
16 фев 20, 09:09    [22080650]     Ответить | Цитировать Сообщить модератору
 Re: Lock-free кольцевой буфер.  [new]
pvv.pas
Member

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

В комплекте black shark есть коллекция TQueueFIFO<T> для пары потоков отлично работает без использования системных средств синхронизации. Но я использовал только для асинхронной очереди, т.е. с возможностью потерь в случае переполнения. Синхронный режим возможно не будет работать, хотя опция есть. Посмотрел код, как по мне - доработать не проблема.
16 фев 20, 11:59    [22080680]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить