DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: 19137911446
今日帖子: 18
在线用户: 17
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/7/29 10:39:45
标题:
线程等待的问题,请赐教,谢谢 浏览:1330
加入我的收藏
楼主: 例:

procedure S1;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    ..........
  end).start;
end;

procedure S2;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    ..........
  end).start;
end;

procedure SS;
begin
  S1;
  S2:
  TThread.CreateAnonymousThread(procedure()
  begin
    ..........
  end).start;
end;

如何在SS中,让S1执行完再执行S2,等S2执行完之后,再执行SS中的匿名线程?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 luckyrandom (luckyrandom) ★☆☆☆☆ -
普通会员
2023/7/29 11:54:44
1楼: 设个变量,甚至可以到数据库上做标记判断
----------------------------------------------
SQL SERVER DBA QQ:315054403 曾经的Delphier  缘在上海
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2023/7/29 12:08:00
2楼: 临界区、互斥对象、信号量
手段太多了。
----------------------------------------------
--
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/7/29 12:14:53
3楼: 你把3个线程内容写到一个里不好么
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 doersoft (hnysoft.com) ★☆☆☆☆ -
普通会员
2023/7/29 15:33:52
4楼: 窗体自定义Message,第一个线程完成,发送msg到窗体句柄[非阻塞],窗体的自定义消息收到后,启动下一个.
----------------------------------------------
delphi|vue|golang hnysoft|hnyerp+mes+srm
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/7/29 19:54:32
5楼: implementation

{$R *.dfm}

uses SyncObjs;

var
  FinishEvent: TSimpleEvent;

procedure S1;
begin
  FinishEvent.ResetEvent;
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    FinishEvent.SetEvent;
  end).Start;

  while FinishEvent.WaitFor(50) = wrTimeout do // 等待线程完成
    Application.ProcessMessages;
end;

procedure S2;
begin
  FinishEvent.ResetEvent;
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    FinishEvent.SetEvent;
  end).Start;

  while FinishEvent.WaitFor(50) = wrTimeout do // 等待线程完成
    Application.ProcessMessages;
end;

procedure SS;
begin
  S1;
  S2;

  TThread.CreateAnonymousThread(procedure()
  begin
    //......
  end).Start;
end;


procedure TForm3.FormCreate(Sender: TObject);
begin
  SS;
end;

initialization
  FinishEvent := TSimpleEvent.Create;

finalization
  FinishEvent.Free;
----------------------------------------------
-
作者:
男 jwj76 (禁卫) ▲△△△△ -
普通会员
2023/7/29 21:22:49
6楼: 既然是顺序执行三个线程,可以写到一个线程里就可以了。没有必要写三个。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2023/7/30 0:26:30
7楼: program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Classes;

function S1: TThread;
begin
  Result := TThread.CreateAnonymousThread(procedure()
  begin
    TThread.Sleep(9000);
    Writeln('s1 ...');
  end);
  Result.start;
end;

function S2: TThread;
begin
  Result := TThread.CreateAnonymousThread(procedure()
  begin
    TThread.Sleep(1000);
    Writeln('s2 ...');
  end);
  Result.start;
end;

function SS: TThread;
begin
  var t1 := S1;
  while not T1.Finished do ;

  var t2 := S2;
  while not t2.Finished do ;

  Result := TThread.CreateAnonymousThread(procedure()
  begin
    TThread.Sleep(1000);
    Writeln('ss ...');
  end);
  Result.Start;
end;

begin
  try
    var s: string;
    Writeln('begin...');
    var t3 := SS;
    while not T3.Finished do ;
    Writeln('end...');
    Readln(s);
    Writeln(s);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
----------------------------------------------
学无止境
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/7/30 1:02:48
8楼: s1和S2是个独立的功能,而ss却需要却需要他们执行完之后的结果才能正确执行,所以就有了这个需求,当然也可以在SS里,把S1 跟S2的代码再复制过去……,这样的代码就重复的太多了,谢谢大家留言
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 myy (myy) ★☆☆☆☆ -
盒子活跃会员
2023/7/30 10:12:31
9楼: s1和S2既然是两个独立的功能,那可以写成普通函数形式。一个函数,既可以直接调用,也可以放到单独线程中调用,这样代码也不会重复啊。
----------------------------------------------
-
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/7/30 10:43:55
9楼: 使用发送消息的方法比较合理一点,不会临时堵死主线程
----------------------------------------------
-
作者:
男 hs_kill (lzl_17948876) ★☆☆☆☆ -
普通会员
2023/7/30 11:04:30
10楼: S1/S2异步执行 全部执行完毕后执行S3

可以考虑使用System.Threading中的TTask
S1/S2正常TTask.start

S3中TTask.WaitForAll(tasks);然后执行
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/7/30 12:17:58
11楼: @sxfgf  as you needs execute S3 only after S1 and S2 run, then I think that you needs use "IFuture" tasks.

https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Using_TTask.IFuture_from_the_Parallel_Programming_Library

S1 = IFuture task
S2 = IFuture task

S3 = your thread default or a task
 S3 =  {
     a := S1;
     b := S2;
      .... 
    }

that way, S3 will receive the values after  S1 and S2 run
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 chencong5025 (Nicosoft) ▲▲▲△△ -
普通会员
2023/7/30 12:39:02
12楼: 我发现Delphi的论坛 经常不是解决问题 而是解决提问的人按此在新窗口浏览图片 按此在新窗口浏览图片
----------------------------------------------
-
作者:
男 letianwuji (大器晚成) ▲▲▲▲▲ -
普通会员
2023/7/30 13:03:01
13楼: procedure AsyncAwaitTh(async, await: TProc);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      async();

      TThread.Queue(nil,
        procedure
        begin
          await();
        end
      ); // TThread.Queue
    end
  ).Start;
end;
----------------------------------------------
相信自己,若自己都不相信,那还有谁可信。
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/7/30 14:57:18
14楼: implementation

{$R *.dfm}

var
  FinishCount: Integer;

procedure S1;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    AtomicIncrement(FinishCount);
  end).Start;
end;

procedure S2;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    AtomicIncrement(FinishCount);
  end).Start;
end;

procedure SS;
begin
  S1;
  S2;

  TThread.CreateAnonymousThread(procedure()
  begin
    while FinishCount < 2 do Sleep(50);
    //......
  end).Start;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SS;
end;

initialization
  FinishCount := 0;

end.
----------------------------------------------
-
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/7/30 15:16:03
15楼: 这个会比较好,没有任何等待状态:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
const
  WM_Finish = WM_USER + 100;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FinishCount: Integer;
    procedure S1;
    procedure S2;
    procedure SS;
    procedure WmFinish(var Msg: TMessage); Message WM_Finish;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FinishCount := 0;
  S1;
  S2;
end;

procedure TForm1.S1;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    PostMessage(Handle, WM_Finish, 0, 0);
  end).Start;
end;

procedure TForm1.S2;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
    PostMessage(Handle, WM_Finish, 0, 0);
  end).Start;
end;

procedure TForm1.WmFinish(var Msg: TMessage);
begin
  Inc(FinishCount);
  if FinishCount = 2 then SS;
end;

procedure TForm1.SS;
begin
  TThread.CreateAnonymousThread(procedure()
  begin
    //......
  end).Start;
end;

end.
----------------------------------------------
-
作者:
男 doersoft (hnysoft.com) ★☆☆☆☆ -
普通会员
2023/7/31 1:35:06
16楼: 楼上的办法就是我的说法,呵呵.
----------------------------------------------
delphi|vue|golang hnysoft|hnyerp+mes+srm
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/7/31 8:39:38
17楼: @doersoft 你说的对
----------------------------------------------
-
作者:
男 kenliaoliao (ben) ★☆☆☆☆ -
普通会员
2023/7/31 10:08:25
18楼: bluestorm8 的方法比较好
----------------------------------------------
-
作者:
男 doersoft (hnysoft.com) ★☆☆☆☆ -
普通会员
2023/7/31 16:02:55
19楼: 非常良好的讨论~~~
----------------------------------------------
delphi|vue|golang hnysoft|hnyerp+mes+srm
作者:
男 roadrunner (roadrunner) ★☆☆☆☆ -
盒子活跃会员
2023/7/31 17:05:38
20楼: S1,S2,SS为三个普通函数,只执行逻辑代码,里头不要有线程相关代码

你的目标可以这样实现:
Task.Run(procedure begin
  S1;
  S2;
  SS;
end);

这在代码上更简洁,而且性能上也大大优于CreateAnonymousThread, 按你原来的思路调用一次创建了3个线程,而用Task.Run一次线程创建的操作都不会有,创建线程是很慢的操作,应当尽量避免
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/7/31 18:22:05
21楼: 如果代码逻辑上,确实是 S1, S2, S3 顺序执行,确实如20楼所说。

如果代码逻辑上,还有其它问题,导致非要几个线程来回折腾,线程之间的同步,正常的做法是使用 TEvent 来做。

也就是第二个线程被一个 TEvent.Wait 阻塞,第一个线程执行完后给那个 TEvent 做一个 SetEvent 操作,就解除了第二个线程的阻塞,第二个线程就可以开始跑了。

第三个线程,也一样采用上述方式。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/7/31 18:23:22
22楼: 如果你不想用 TEvent 阻塞,那就是土办法,第二个线程跑循环判断一个变量,这个变量有没有被第一个线程设置,有则说明第一个线程执行完毕,则第二个线程可以继续向下执行了。这个办法比较土,但有效。
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/1 3:04:49
23楼:
In fact, YOU DONT NEED ANY LOCK / UNLOCK in your threads!
Just use the "IFUTURE" tasks to call the resulted when you needs it!
The procedures will called just when necessary, not before, not later!


type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
...
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  System.Threading;

var
  LTaskRUN: ITask;

function MyFunc001ToReturnAnyValue: integer;
var
  LResult: integer;
begin
  sleep(400); // simulating a delay...
  //
  LResult := 10;
  result  := LResult;
  //
  TThread.Queue(nil, // just for tests...
    procedure
    begin
      Form1.Memo1.Lines.Add(TimeToStr(now, FormatSettings) + ', Func001 = ' + LResult.ToString);
    end);
end;

function MyFunc002ToReturnAnyValue: integer;
var
  LResult: integer;
begin
  sleep(750); // simulating a delay...
  //
  LResult := 20;
  result  := LResult;
  //
  TThread.Queue(nil, // just for tests...
    procedure
    begin
      Form1.Memo1.Lines.Add(TimeToStr(now, FormatSettings) + ', Func002 = ' + LResult.ToString);
    end);
end;

function MyFunc003ToReturnAnyValue(AValue001, AValue002: integer): integer;
var
  LResult: integer;
begin
  sleep(500); // simulating a delay...
  //
  LResult := AValue001 + AValue002;
  result  := LResult;
  //
  TThread.Queue(nil, // just for tests...
    procedure
    begin
      Form1.Memo1.Lines.Add(TimeToStr(now, FormatSettings) + ', Func003 = ' + LResult.ToString);
    end);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LFutureOne: IFuture<integer>;
  LFutureTwo: IFuture<integer>;
  //
  LText       : string;
  LResulted   : integer;
  LTimeElapsed: UInt64;
begin
  Button1.Enabled := false; // to avoid "double click"...
  //
  FormatSettings.LongTimeFormat := 'hh:nn:ss.zzz';
  //
  Memo1.Lines.Clear;
  //
  LFutureOne := TTask.Future<integer>(MyFunc001ToReturnAnyValue); // 400ms
  LFutureTwo := TTask.Future<integer>(MyFunc002ToReturnAnyValue); // 750ms
  //
  LTaskRUN := TTask.Run(
    procedure
    begin
      LTimeElapsed := GetTickCount64;
      //
      // when "LFutureXXXX.VALUE" is called, then it will be executed (in fact)!!!
      LResulted := MyFunc003ToReturnAnyValue(LFutureOne.Value, LFutureTwo.Value); // 500 ms
      //
      LTimeElapsed := GetTickCount64 - LTimeElapsed;
      //
      LFutureOne := nil;
      LFutureTwo := nil;
      //
      // Total time: Func002 + Func003 = 1250ms (+/-)
      LText := format('S3 = S1 + S2 is: %d, at %d (ms)', [LResulted, LTimeElapsed]);
      //
      Form1.Memo1.Lines.Add(TimeToStr(now, FormatSettings) + ', TTask.RUN(...) ' + LText);
      //
      Button1.Enabled := true;
    end);
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if (LTaskRUN = nil) then
    CanClose := true
  else
    CanClose := LTaskRUN.Status in [TTaskStatus.Completed, TTaskStatus.Canceled, TTaskStatus.Exception];
  //
  if CanClose then
    LTaskRUN := nil;
end;

initialization

ReportMemoryLeaksOnShutdown := true;

end.
此帖子包含附件:
GIF 图像
大小:247.4K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/1 3:08:21
24楼: SUMMARY:

procedure TForm1.Button1Click(Sender: TObject);
var
  LFutureOne: IFuture<integer>;
  LFutureTwo: IFuture<integer>;
begin
  //  you can invert the sequence if needs!
  LFutureOne := TTask.Future<integer>(MyFunc001ToReturnAnyValue); // MyFunc002...
  LFutureTwo := TTask.Future<integer>(MyFunc002ToReturnAnyValue); // MyFunc001...
  //
  TTask.Run(
    procedure
    begin
      MyFunc003ToReturnAnyValue(   LFutureOne.Value, LFutureTwo.Value  );
    end);
..........
Func001 = 400ms
Func002 = 750ms
Func003 = 500ms

Total Time:  Func2 + Func3 ( 750 + 500 ) = 1250 (+/-) ms

---------- REMEMBER THIS: ----------
Your tasks is not necessary use "THREADs" because you do the "sequencial tasks"!
--> Func3 wait Func2... Func2 wait Func1.


as said above, better is:

Task.RUN(
  procedure
  begin
    Func1;
    Func2;
    Func3;
  end);
);
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/2 10:56:42
25楼: a little fix to avoid "close" form whike the tasks is running!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/8/2 15:48:04
26楼: 人家的要求是S1的线程和S2线程可以同时运行,S1的线程和S2的线程都运行完毕后, 才开始运行SS的线程, 所以不存在S1、S2、SS顺序运行的问题
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/2 21:39:41
27楼: using "TTASK" ( IFUTURE ) S1 and S2 is called and run in "parallel", then, S1 and S2 is concurrent thread

S1 = 400ms  
S2 = 750ms -- here, S1 already was completed because needs only 400ms
S3 = 500ms  

sequence:

1º - S3 run and call S1 and S2
2º - S1 and S2 execute the instructions in parallel
3º - S3 receive the values from S1 and S2
4º - S3 is concluded!


NOTE: comment all "SLEEP(...)" functions
此帖子包含附件:
PNG 图像
大小:18.8K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2023/8/3 0:22:31
28楼: 如果绑定在windows系统上,可以直接用waitfor函数。
比如:
var h: array[0..2] of thandle;
..
h[0] := createthread(...);
h[1] := createthread(...);

while waitformultipleobjectsex(2, @h[0], true, 10, true) = wait_timeout do
  application.handlemessage();

h[2] := createthread(...);
while waitforsingleobject(h[2], 10) = wait_timeout do
  application.handlemessage();

closehandle(...);
...



如果要考虑跨平台,那就用event或者mutex这些也是一样的。
----------------------------------------------
--
作者:
男 bluestorm8 (bluestorm) ▲▲△△△ -
普通会员
2023/8/3 8:35:18
29楼: 本来是很简单的事情,为什么要搞得那么复杂?
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行121.0938毫秒 RSS