Совместное использование нативной переменной между потоками Delphi

Я предполагал, что если общая переменная между потоками имеет собственный тип, атомарность должна делать эту работу.

Но в соответствии с выводом кода ниже, это не так, по крайней мере, для Delphi.

Поток t1 просто увеличивает счетчик в 10 раз. В то же время поток t2 уменьшает счетчик в 10 миллионов раз. Таким образом, ожидаемое значение счетчика в конце равно 0, но я каждый раз читаю разные значения.

Как правильно делить нативную переменную между потоками в Delphi без блокировки?

procedure TForm1.Button1Click(Sender: TObject);
var
  t1, t2: TThread;
  Counter: NativeInt;
begin
  Counter := 0;

  // first thread to increment shared counter
  t1 := TThread.CreateAnonymousThread(
    procedure ()
    var
      i: Integer;
    begin
      for i := 1 to 10000000 do
        Inc(Counter);
    end
  );

  // second thread to decrement shared counter
  t2 := TThread.CreateAnonymousThread(
    procedure ()
    var
      i: Integer;
    begin
      for i := 1 to 10000000 do
        Dec(Counter);
    end
  );

  t1.FreeOnTerminate := false;
  t2.FreeOnTerminate := false;

  // start threads
  t1.Start;
  t2.Start;

  // wait for them to finish
  t1.WaitFor;
  t2.WaitFor;

  t1.Free;
  t2.Free;

  // print the counter, expected counter is 0
  Caption := IntToStr(Counter);
end;

1 ответ

Решение

Чтение и запись выровненных переменных является атомарным. Но проблема в том, что когда вы используете inc а также dec Вы оба читаете и пишете. Выполняя два обращения к памяти, составная операция перестает быть атомарной.

Вместо этого используйте атомарные функции приращения. TInterlocked методы класса или AtomicIncrement,

Что касается того, что является родным о NativeInt, что относится к его размеру. Это целочисленный тип того же размера, что и указатель. Итак, 32 бита в 32-битном процессе, 64 бита в 64-битном процессе. Эти типы редко используются для чистого кода Delphi, обычно для взаимодействия со сторонними библиотеками, которые могут объявлять типы дескрипторов, используя целочисленные значения указателя.

Другие вопросы по тегам