Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Поток без синхронизации

Delphi , Компоненты и Классы , Потоки



Автор: Xavier Pacheco

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TMainForm = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    procedure ThreadsDone(Sender: TObject);
  end;

  TFooThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

const
  MaxSize = 128;

var
  NextNumber: Integer = 0;
  DoneFlags: Integer = 0;
  GlobalArray: array[1..MaxSize] of Integer;

function GetNextNumber: Integer;
begin
  Result := NextNumber; // return global var
  Inc(NextNumber); // inc global var
end;

procedure TFooThread.Execute;
var
  i: Integer;
begin
  OnTerminate := MainForm.ThreadsDone;
  for i := 1 to MaxSize do
  begin
    GlobalArray[i] := GetNextNumber; // set array element
    Sleep(5); // let thread intertwine
  end;
end;

procedure TMainForm.ThreadsDone(Sender: TObject);
var
  i: Integer;
begin
  Inc(DoneFlags);
  if DoneFlags = 2 then // make sure both threads finished
    for i := 1 to MaxSize do
      { fill listbox with array contents }
      Listbox1.Items.Add(IntToStr(GlobalArray[i]));
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
  TFooThread.Create(False); // create threads
  TFooThread.Create(False);
end;

end.

Это проект Delphi, демонстрирующий использование нескольких потоков без синхронизации. Программа создает два потока, TFooThread, которые заполняют массив числами и добавляют содержимое массива в список когда оба потока закончат работу.

Обзор кода:

  1. Главная форма (TMainForm) имеет кнопку и список.
  2. Когда кнопка нажата, она создает два экземпляра TFooThread.
  3. Каждый экземпляр TFooThread выполняется в своем потоке, заполняя массив числами с помощью функции GetNextNumber.
  4. Потоки спят на 5 миллисекунд между каждым итерацией для имитации выполнения каких-либо задач.
  5. Когда оба потока закончат работу (DoneFlags = 2), они вызывают процедуру ThreadsDone на главной форме.
  6. Процедура ThreadsDone заполняет список содержимым массива.

Проблема с этим кодом заключается в том, что он не синхронизирует доступ к общим ресурсам (массиву и списку). Это означает, что потоки могут перезаписать изменения друг друга,leading to incorrect results.

Чтобы решить эту проблему, можно использовать синхронизационные примитивы, такие как критические секции, семафоры или блоки для защиты доступа к общим ресурсам. Например, можно обернуть код в процедуре ThreadsDone критической секцией:

procedure TMainForm.ThreadsDone(Sender: TObject);
begin
  Inc(DoneFlags);
  if DoneFlags = 2 then
  begin
    CRITICAL_SECTION.Enter;
    try
      for i := 1 to MaxSize do
        Listbox1.Items.Add(IntToStr(GlobalArray[i]));
    finally
      CRITICAL_SECTION.Leave;
    end;
  end;
end;

Альтернативно, можно использовать блок для защиты доступа к общим ресурсам:

procedure TMainForm.ThreadsDone(Sender: TObject);
begin
  Inc(DoneFlags);
  if DoneFlags = 2 then
  begin
    LOCK.Enter;
    try
      for i := 1 to MaxSize do
        Listbox1.Items.Add(IntToStr(GlobalArray[i]));
    finally
      LOCK.Leave;
    end;
  end;
end;

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

Альтернативным решением является использование конкуретного данных, таких как TThreadList или TConcurrentArray, которые предназначены для безопасного использования с несколькими потоками без необходимости в явном синхронизации:

procedure TFooThread.Execute;
begin
  OnTerminate := MainForm.ThreadsDone;
  for i := 1 to MaxSize do
  begin
    GlobalArray.Add(GetNextNumber);
    Sleep(5);
  end;
end;

procedure TMainForm.ThreadsDone(Sender: TObject);
begin
  Inc(DoneFlags);
  if DoneFlags = 2 then
  begin
    Listbox1.Items.Assign(GlobalArray);
  end;
end;

В этом примере GlobalArray - это TThreadList, предназначенный для безопасного использования с несколькими потоками. Процедура ThreadsDone просто присваивает содержимое GlobalArray списку когда оба потока закончат работу.

В статье описывается пример использования потоков без синхронизации в Delphi, где два потока изменяют общую переменную и заполняют массивом, а затем результаты выводятся в список.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Потоки ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-16 01:11:06/0.0033800601959229/0