BeginThread 结构 - Delphi

发布于 2024-10-13 19:35:28 字数 1621 浏览 2 评论 0原文

我现在已经有了一个即将完成的应用程序,我想要实现的下一个功能是线程。我选择使用 BeginThread(),尽管我知道 delphi 中的 TThread。我遇到的问题是 BeginThread() 调用的结构。通常,程序中调用我想要线程化的函数的行是

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);

op ,它是一个整数。

我将其切换为从中创建线程的行是

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x);

从我可以找到的有关如何实际使用 BeginThread() 的少量信息中,这应该是一个很好的调用,但是在编译时我得到的只是有关的编译器错误我的 BeginThread() 语句参数的结构。

编辑信息。

当前调用 CompareFiles 的过程是

procedure TForm1.Panel29Click(Sender: TObject);
var
op,x : integer;

begin
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then
        begin
          op := 3;
          if RadioButton7.Checked = True then op := 0;
          if RadioButton3.Checked = True then op := 1;
          if RadioButton4.Checked = True then op := 2;
          if RadioButton5.Checked = True then op := 3;
          if RadioButton6.Checked = True then op := 4;
          CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
        end;
end;

如果我按照几个人的建议使用 TThread,并且如下面 Rob 所示,我很困惑 a) 如何将 op、Edit3/4.Text 和 StringGrid2 传递给比较文件。从我见过的 TThread 示例猜测,我想我应该用 TCompareFilesThread.Execute 替换上面的代码,并将 Panel29Click 中的当前代码放入 TCompareFilesThread.Create 中,然后添加

FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;

到此

FEdit3Text := Form1.Edit3.Text;
FEdit4Text := Form1.Edit4.Text;
FGrid := Form1.StringGrid2;

但我有一种完全不合时宜的挥之不去的感觉。

I've got a almost completed app now and the next feature I want to implement is threading. I chose to go with BeginThread(), although am aware of TThread in delphi. The problem I'm coming across is the structure of BeginThread() call. Normally the line in the program that would call the function I want to be threaded is

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);

op is a integer.

The line I've switched it out for to create a thread from it is

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x);

From the little amount of infromation I can find on how to actually use BeginThread() this should be a fine call, however on compling all I get is complier errors regarding the structure of my BeginThread() statement paramenters.

EDIT FOR INFORMATION.

The current procedure that calls CompareFiles is

procedure TForm1.Panel29Click(Sender: TObject);
var
op,x : integer;

begin
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then
        begin
          op := 3;
          if RadioButton7.Checked = True then op := 0;
          if RadioButton3.Checked = True then op := 1;
          if RadioButton4.Checked = True then op := 2;
          if RadioButton5.Checked = True then op := 3;
          if RadioButton6.Checked = True then op := 4;
          CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
        end;
end;

If I was to use TThread as suggested by a couple of people, and as displayed by Rob below, I'm confused at how a) I would pass op,Edit3/4.Text and StringGrid2 to the CompareFiles. Guessing from the example of TThread I've seen I thought I would replace the code above with TCompareFilesThread.Executeand the put the current code from Panel29Click into TCompareFilesThread.Create and then add

FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;

to this

FEdit3Text := Form1.Edit3.Text;
FEdit4Text := Form1.Edit4.Text;
FGrid := Form1.StringGrid2;

But I've got this nagging feeling that is totally off the mark.

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

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

发布评论

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

评论(1

荭秂 2024-10-20 19:35:28

这根本不是使用BeginThread 的方式。该函数需要一个指向带有一个参数的函数的指针,但您尝试调用的函数需要四个参数。您为 BeginThread 提供的用于转发到线程过程的一个参数是一个字符串,但您显然希望某种魔法能够将该字符串转换为这些变量包含的值。

这不是 Delphi 的工作方式,即使对于那些可以做类似事情的语言,通常也不鼓励实际它。

要将多个参数传递给 BeginThread,请定义一个包含您需要的所有值的记录,并定义一个记录指针:

type
  PCompareFilesParams = ^TCompareFilesParams;
  TCompareFilesParams = record
    Edit3Text,
    Edit4Text: string;
    Grid: TStringGrid;
    Op: Integer;
  end;

更改 CompareFiles 以接受指向该记录的指针:

function CompareFiles(Params: PCompareFilesParams): Integer;

要启动线程,您需要分配该记录的一个实例并填充其字段:

var
  Params: PCompareFilesParams;
begin
  New(Params);
  Params.Edit3Text := Edit3.Text;
  Params.Edit4Text := Edit4.Text;
  Params.Grid := StringGrid2;
  Params.Op := op;
  BeginThread(nil, 0, @CompareFiles, Params, 0, x);

像这样实现CompareFiles,以便在线程终止之前释放该记录:

function CompareFiles(Params: PCompareFilesParams): Integer;
begin
  try
    // <Normal implementation goes here.>
  finally
    Dispose(Params);
  end;
end;

您可以将其全部设置为不过,如果您只使用 TThread 就会容易得多。您可以让您的后代类在其构造函数中具有任意数量的参数,这样您就不必费力地动态分配和释放特殊记录。

type
  TCompareFilesThread = class(TThread)
  private
    FEdit3Text,
    FEdit4Text: string;
    FGrid: TStringGrid;
    FOp: Integer;
    procedure Execute; override;
  public
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer);
    property ReturnValue;
  end;

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
  FEdit3Text := Edit3Text;
  FEdit4Text := Edit4Text;
  FGrid := Grid;
  FOp := Op;
end;

procedure TCompareFilesThread.Execute;
begin
  ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp);
end;

您只需实例化该类并让它运行,而不是调用 BeginThread

var
  ThreadRef: TThread;


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op);

使用线程还有更多内容,例如知道线程何时完成运行,但我认为您已经足够开始了。不过,最后一件事要注意的是,TStringGrid 是一个 VCL 控件。您不能从您创建的这个新线程中对其执行任何操作(无论您最终如何创建它)。您对网格控件所做的一切都需要从主线程完成。使用 TThread.SynchronizeTThread.Queue 将任何 VCL 操作转移到主线程上。您的文件比较线程将等待同步操作完成,但它将继续运行,而不等待排队操作完成。

That's not at all the way to use BeginThread. That function expects a pointer to a function that takes one parameter, but the function you're trying to call wants four. The one parameter you're giving to BeginThread for it to forward to the thread procedure is a string, but you evidently hope that some sort of magic will turn that string of characters into the values that those variables contain.

That's not how Delphi works, and even for the languages that can do something like that, it's generally discouraged to actually do it.

To pass multiple parameters to BeginThread, define a record with all the values you'll need, and also define a record pointer:

type
  PCompareFilesParams = ^TCompareFilesParams;
  TCompareFilesParams = record
    Edit3Text,
    Edit4Text: string;
    Grid: TStringGrid;
    Op: Integer;
  end;

Change CompareFiles to accept a pointer to that record:

function CompareFiles(Params: PCompareFilesParams): Integer;

To start the thread, you'll need to allocate an instance of that record and populate its fields:

var
  Params: PCompareFilesParams;
begin
  New(Params);
  Params.Edit3Text := Edit3.Text;
  Params.Edit4Text := Edit4.Text;
  Params.Grid := StringGrid2;
  Params.Op := op;
  BeginThread(nil, 0, @CompareFiles, Params, 0, x);

Implement CompareFiles like this so that the record will get freed before the thread terminates:

function CompareFiles(Params: PCompareFilesParams): Integer;
begin
  try
    // <Normal implementation goes here.>
  finally
    Dispose(Params);
  end;
end;

You can make it all a lot easier if you just use TThread, though. You can make your descendant class have as many parameters as you want in its constructor, so you don't have to mess around with dynamically allocating and freeing a special record.

type
  TCompareFilesThread = class(TThread)
  private
    FEdit3Text,
    FEdit4Text: string;
    FGrid: TStringGrid;
    FOp: Integer;
    procedure Execute; override;
  public
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer);
    property ReturnValue;
  end;

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
  FEdit3Text := Edit3Text;
  FEdit4Text := Edit4Text;
  FGrid := Grid;
  FOp := Op;
end;

procedure TCompareFilesThread.Execute;
begin
  ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp);
end;

Instead of calling BeginThread, you just instantiate the class and let it run:

var
  ThreadRef: TThread;


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op);

There's more to using threads, such as knowing when the thread has finished running, but I think you have enough to get started. One last thing to beware of, though, is that TStringGrid is a VCL control. You mustn't do anything with it from this new thread you create (regardless of how you end up creating it). Eveything you do with the grid control need to be done from the main thread. Use TThread.Synchronize and TThread.Queue to shift any VCL operations onto the main thread. Your file-comparing thread will wait for the synchronized operation to complete, but it will keep running without waiting for a queued operation to complete.

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