如何正确使用TThread

发布于 2024-09-28 22:26:04 字数 2411 浏览 2 评论 0原文

你能帮我一下吗?我正在编写一个组件(类似于 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。如何在它们仍在运行时停止它们?

Could you help me please. I'm writing a component (something like TListView), In my component I perform 3 procedures one by one:

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

I can not understand how to make my component use Threads to perform all these procedures, at least the first one (findFiles). I've tried different ways but nothing comes out.

Here is a scetch of what I have (just a basic example).

 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;

and only then execute the thread to set appropriate icons (SetIcons):

 procedure TSearchThread.DoSearch;
 begin
  SetIcons;
 end;

It worked but with bugs: sometimes my component created icons not for all items, sometimes some items had an icon fully filled with black colour and sometimes I had no icons at all;

then I decided to perform all the 3 procedures in the thread:

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

As a result I had the same bugs with creating Icons and instead of searching in a specified folder it searched in the folder where my application was.

For you to understand me more, I am trying to write a file manager with multiple tabs, so as far as I understand, I need to use Threads so that application will not freeze when dealing with multiple tabs.

Could you help me please to understand how to arrange my code?!!!!
Maybe you could give an example because there in not many documentation concerning Threading.


Hi again.
I've tried both AsyncCalls and OmniThreadLibrary. They both had an example of "Background" file search. First I found AsyncCalls more suitable for my application as it really did its job well. I used AsyncCalls to perform my three procedures and it was what I had been looking for.
I also tried calling my procedures using OmniThreadLibrary but it seemed like they were not performed in a thread.
That's why I prefered AsyncCalls, but I have a question, HOW TO STOP IAsyncCall when it is running?
I mean, for example, as I've mentioned before my application is multitabbed and if a user opens 3 tabs and on each tab executes file searching, then how can I stop file searching on the second tab?

To make it more clear for you to understand what I want to do, here is a sketch:

A form has 3 TMemo, 3 TButton

var 
 a1, a2, a3: IAsyncCall;


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

All the three buttons do the same, except they point to differen 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;

So, if I click all the three buttons, I'll have 3 IAsyncCall running. How to stop any of them while it is still running?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

土豪我们做朋友吧 2024-10-05 22:26:04

使用这样的代码,

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

您根本不使用工作线程 - 所有工作都是通过 Synchronize 调用在主线程中完成的。这是一个不应该使用线程的例子。简而言之,您的执行代码可能如下所示:

 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; 

With the code like this

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

you don't use a worker thread at all - all work is done in the main thread via Synchronize call. That is an example how one should not use threads. In short, your Execute code may look like this:

 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; 
随风而去 2024-10-05 22:26:04

我认为你最好的选择是使用 AsyncCalls 库,非常易于使用,并且在网页中包含一个与您的示例非常相似的演示。

i think wich your best option is use the AsyncCalls library, wich is very easy to use, and in the webpage includes a demo very similar to your example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文