Как правильно использовать TThread - PullRequest
0 голосов
/ 24 октября 2010

Не могли бы вы помочь мне, пожалуйста. Я пишу компонент (что-то вроде TListView), в моем компоненте я выполняю 3 процедуры по одной:

procedure findFiles(Path:String); // using FindFirst, FindNext
procedure ArrangeItems; // assigns Item Position
procedure SetIcons;    // Loads Images, resizes, adds to ImageList

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

Вот пример того, что у меня есть (просто базовый пример).

 type
  TSearchThread = class(TThread)
  private
    SIView: TSIView;
  protected
    procedure Execute; override;
    procedure DoSearch;
  public
    constructor Create(fSIView: TSIView);
  end;



 constructor TSearchThread.Create(fSIView: TSIView);
 begin
  SIView := fSIView;
  FreeOnTerminate := True;
  inherited Create(False);
  Priority := tpLower;
 end;

 procedure TSearchThread.Execute;
 begin
  inherited;
  Synchronize(DoSearch);
 end; 

 first I tried to perform 
   SIView.findFiles('C:\');
   ArrangeItems;

и только затем выполнить поток для установки соответствующих значков (SetIcons):

 procedure TSearchThread.DoSearch;
 begin
  SetIcons;
 end;

Это работало, но с ошибками: иногда мой компонент создавал иконки не для всех элементов, иногда некоторые элементы имели значки, полностью заполненные черным цветом, а иногда у меня вообще не было значков;

тогда я решил выполнить все 3 процедуры в теме:

 procedure TSearchThread.DoSearch;
 begin
  SIView.findFiles('C:\');
  ArrangeItems;
  SetIcons;
 end; 

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

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

Не могли бы вы мне помочь, пожалуйста, чтобы понять, как организовать мой код? !!!! Может быть, вы могли бы привести пример, потому что там не так много документации, касающейся потоков.


Привет еще раз.
Я пробовал оба AsyncCalls и OmniThreadLibrary. У них обоих был пример «фонового» поиска файлов. Сначала я обнаружил, что AsyncCalls больше подходит для моего приложения, поскольку оно действительно хорошо справилось со своей задачей. Я использовал AsyncCalls для выполнения моих трех процедур, и это было то, что я искал. Я также попытался вызвать мои процедуры, используя OmniThreadLibrary, но казалось, что они не были выполнены в потоке. Вот почему я предпочел AsyncCalls, но у меня есть вопрос, КАК ОСТАНОВИТЬ IAsyncCall, когда он работает? Я имею в виду, например, как я уже упоминал до того, как мое приложение является многозадачным, и если пользователь открывает 3 вкладки и на каждой вкладке выполняет поиск файлов, то как мне остановить поиск файлов на второй вкладке?

Чтобы вам было проще понять, что я хочу сделать, вот набросок:

Форма имеет 3 TMemo, 3 TButton

var 
 a1, a2, a3: IAsyncCall;


procedure TForm1.Search(Path:String; MEMO:TMemo);
begin
 /////// Finds files and adds to MEMO 
end;

Все три кнопки работают одинаково, за исключением того, что они указывают на разные TMemo (Memo1, Memo2, Memo3);

procedure TForm1.Button1Click(Sender: TObject);

 procedure DoSearch;
 begin
  Search('C:\', Memo1);     
 end;

begin
  a1 := LocalAsyncCall(@DoSearch);

  while AsyncMultiSync([a1], True, 0) = WAIT_TIMEOUT do
      Application.ProcessMessages;
end;

Итак, если я нажму все три кнопки, у меня будет запущено 3 IAsyncCall. Как остановить любого из них, пока он еще работает?

Ответы [ 2 ]

6 голосов
/ 24 октября 2010

С таким кодом

 procedure TSearchThread.Execute;
 begin
  inherited;
  Synchronize(DoSearch);
 end; 

вы вообще не используете рабочий поток - вся работа выполняется в основном потоке с помощью вызова Synchronize. Это пример того, как не следует использовать потоки. Короче говоря, ваш код Execute может выглядеть так:

 procedure TSearchThread.Execute;
 begin
   if FindFirst(..) then begin
     repeat
       Queue(..); // inform the main thread about the item is found
     until not FindNext(..)
     FindClose;
   end;
   Queue(..); // inform the main thread that the work is completed
              //   and we are about to terminate
 end; 
5 голосов
/ 24 октября 2010

Я думаю, что ваш лучший вариант - использовать библиотеку AsyncCalls, которая очень проста в использовании, и на веб-странице есть демонстрация, очень похожая на ваш пример.

...