delphi中主线程如何等以另一个线程执行完在执行

wangxiubing04535 2010-10-11 10:33:11
我有个主线程中要创建一个线程。线程中主要判断某个任务完成没有,是一个while循环,没执行完就等待。主线程要等子线程执行完才能往下执行,所以我用了个互斥句柄,主线程关键代码是这样子的:
if FPlayFileHandle > 0 then
begin
MyThread := TMyThead.Create(True);
MyThread.FPlayFileHandle := FPlayFileHandle;
MyThread.Resume;
nret := WaitForSingleObject(hMutex, INFINITE);
ReleaseMutex(hMutex);
end;
子线程中关键代码:
hMutex := CreateMutex(nil, false, nil);
while true do
begin
nPos := BSR_DVR_DownFileGetPos(FPlayFileHandle) div 10;
if (npos < 0) or (npos >= 100) then
begin
FreeOnTerminate := True;
CloseHandle(hMutex);
我就是不知道这样的对互斥变量操作过程能让子线程先执行完吗,网上查资料可以的,可是子线程没执行完,主线程就接着执行了,请问大家我那个地方出问题了,怎么改?
...全文
1347 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
wxieyang 2010-10-12
  • 打赏
  • 举报
回复
不要再主线程中调用等待函数,你的子线程完全可以采用通知的方式将当前的进度通知给主线程。
为什么一定要在主线程中自己用循环去等待呢?
主线程中的消息循环本身就是最好的等待方式,最简单的方式,你自定义一个消息,子线程向主线程发消息通知自己的进度就是了。

换个思路,问题可能很简单的。

比如:
在主线程的显示进度的窗体中定义一个消息响应函数,在消息响应函数中刷新进度信息。
子线程在适当的时候,采用sendmessage的方式向进度显示窗体发送消息,在消息中携带进度相关的数据供显示进度窗体的消息响应函数来处理。
lght 2010-10-12
  • 打赏
  • 举报
回复
把主线程中的while循环放到一个子线程里
wangxiubing04535 2010-10-12
  • 打赏
  • 举报
回复
用带while的MSGWaitForMultipleObjects没有阻塞掉时间线程。
lght 2010-10-12
  • 打赏
  • 举报
回复
有那个ocx窗体的句柄就可以发消息。
你阻塞了主线程,界面还有响应?
wangxiubing04535 2010-10-12
  • 打赏
  • 举报
回复
貌似用MSGWaitForMultipleObjects可以显示进度值了了,主线程的while并不会阻塞掉timer时钟,只是timer时钟线程随机执行导致取得进度值不是实时下载的进度。我的timer事件是在调用下载主线程后激发的,主线程有前面的while循环所以延后激发了。我对ocx不是很熟悉,下载窗体已经封转进ocx中,我不知道怎么向已封装进ocx中窗体发送消息,(主线程没被封转进ocx中,只是外部普通的pas)。再问下,在外部可以向ocx中窗体发送消息吗?我想说确实应直接使用TThread类,后来才发现要用Terminated属性,二楼说的是有道理的。
lght 2010-10-11
  • 打赏
  • 举报
回复
只有一个线程在等待hMutex,当然是立即就返回了。
仔细看看windows核心编程。

Mutex创建后,改互斥对象计数器为0,表示所保护的资源没有线程访问,调用waitforsingleobject将查看计数器,为0时才能访问保护的资源,同时将计数器加1,其它所有访问改资源的线程将被置于等待状态。
等待多个用WaitForMultipleObjects。

如果你要用Mutex,主线程和子线程都得调用waitforsingleobject,并且主线程的waitforsingleobject还必须在子线程的waitforsingleobject之后执行。
SQLDebug_Fan 2010-10-11
  • 打赏
  • 举报
回复
可以这样写WaitForSingleObject(MyThread.Handle, INFINITE);
SQLDebug_Fan 2010-10-11
  • 打赏
  • 举报
回复
WaitForSingleObject等待线程句柄返回就可以了,WaitForSingleObject(hMutex, INFINITE)这样很快就返回了。
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
子线程代码
//hMutex := CreateMutex(nil, false, nil);
while true do
begin
nPos := BSR_DVR_DownFileGetPos(FPlayFileHandle) div 10;
if (npos < 0) or (npos >= 100) then
begin
FreeOnTerminate := True;
//CloseHandle(hMutex);
if npos = 100 then
Break
else
begin
npos := nPos * 1;
TraceLog(IntToStr(FPlayFileHandle) + '下载文件时发生异常le npos:' +inttostr(npos));
Break;
end;
end
else
begin
TraceLog('下载句柄:'+ inttostr(FPlayFileHandle) + '正在下载文件');
Sleep(1000);
end;
end; // while
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
貌似线程同步的方法有四种吧,我和你说的都是可行的,只是我对我使用mutex的过程不够自信,不知道错了没有,我的线程是继承TThread类,另外,主线程在执行时其实有一个timer时间事件线程也执行了,用于在窗体中显示下载进度值的,可是没能显示出来,是sleep的原因吗
bdmh 2010-10-11
  • 打赏
  • 举报
回复
检查一下WaitForSingleObject的返回值是什么
kye_jufei 2010-10-11
  • 打赏
  • 举报
回复
unit Unit1;

interface

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

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
threadid:dword;
hthread:thandle;
procedure tt();

implementation

{$R *.dfm}

procedure tt();//线程要执行的函数
var i:integer;
begin
for i:=0 to 20000 do
form1.Edit1.Text:=inttostr(i);
end;

procedure TForm1.Button1Click(Sender: TObject);//
begin
hthread:=createthread(nil,0,@tt,nil,0,threadid); //创建线程并立即执行
if hthread=0 then
messagebox(handle,'创建失败',nil,mb_ok);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
suspendthread(hthread);//挂起线程
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
resumethread(hthread);//恢复线程
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
terminatethread(hthread,2);//结束线程
end;
end.
kye_jufei 2010-10-11
  • 打赏
  • 举报
回复
首先在DELPHI裏,有DELPHI自己做的線程類,最好用它。

還有就是這種方法用在多線程裏就一定要有 CreateEvent ,ResetEvent 完成一個再下一個。不然就同辦法同步了。
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
用mutex也没有问题吧,希望大家指出我的错误在哪里,我会试下二楼的方法
lght 2010-10-11
  • 打赏
  • 举报
回复
没必要用mutex吧
子线中:
FreeOnTerminate := False;

主线程创建子线程:
MyThread := TMyThead.Create(True);
MyThread.Resume;
MyThread.WaitFor;//WaitForSingleObject(MyThread.Handle, INFINITE)也可以
MyThread.Free;
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
timer事件可以每隔一秒在下载窗体上显示下载的进度,而下载窗体封装进ocx控件里面了,当单击下载窗体的下载按钮会激发timer事件,我想能不能运行timer线程,因为下载的文件比较大,不显示进度感觉不太好,有办法吗,呵呵
SQLDebug_Fan 2010-10-11
  • 打赏
  • 举报
回复
这个问题可以在TThread的OnTerminate事件中来通知下载完成。
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
phandle就是MyThread.Handle
wangxiubing04535 2010-10-11
  • 打赏
  • 举报
回复
在主线程中调用WaitForSingleObject(MyThread.Handle, INFINITE)会导致死锁;所以我在主线程中又用了以下代码:
while true do
begin
nret := MSGWaitForMultipleObjects(1, pHandle, False, INFINITE, (QS_INPUT or QS_POSTMESSAGE or QS_PAINT
or QS_HOTKEY or QS_SENDMESSAGE));
if nret = WAIT_OBJECT_0 then
break
else
begin
peekMessage(msg, 0, 0, 0, PM_REMOVE);
DispatchMessage(msg);
end;

end;

MSGWaitForMultipleObjects最后一个参数没有用QS_ALLINPUT,是考虑到不过滤掉QS_TIMER消息
我还有一个时钟事件线程会在主线程(一个下载文件的函数)运行时就会执行,可是主线程中的while会阻塞掉时钟事件线程,真是头疼,哪位大侠在帮忙出下主意,while循环会阻塞掉时钟事件吗,有什么方法呢,先谢谢了。
keeley20 2010-10-11
  • 打赏
  • 举报
回复
加互斥标示
加载更多回复(5)
Direct Oracle Access 组件有两种版本,Direct Oracle Access Standard version 和 Direct Oracle Access Object version Object版允许你通过TOracleObject和TOracleReference 对象使用 Oracle8的对象扩展。 如果您正在使用 Borland 的 Delphi 或 C++Builder 开发 Oracle 应用程序,那么 Direct Oracle Access 组件集将帮助您实现 Borland 开发工具和 Oracle 数据库系统之间的无缝集成。 使用 Direct Oracle Access,应用程序可以充分利用两个产品的优势。 主要特性: 高性能 ——Oracle的性能特性对于在线业务和批处理程序非常有用。通过Direct Oracle Access,能够直接访问Oracle接口,从而使得标准的数据库访问函数实现性能最优。而该组件集还支持Array Fetching, Array DML, PL/SQL Blocks, PL/SQL Tables、本地语句缓存和直接路径装载引擎,进一步优化了您程序的性能关键函数。 程序发布方便 ——Direct Oracle Access程序无需BDE或ODBC等中间件,只要求Oracle SQL*Net 或Net8。这样,您在布署应用程序时,无需考虑中间件的安装,避免了许多版本依赖性和配置问题。 Oracle Package支持 ——Oracle数据库中的多数PL/SQL代码被编程为程序包。Direct Oracle Access提供了一个TOraclePackage组件,您可以方便的调用打包后的程序单元,而无需对这些程序单元和参数做细节说明。 Direct Oracle Access还含有一个Package向导,可以生成类,用以封装程序单元,并记录程序包中定义的类型。最终,将您的Oracle程序包变为Object Pascal或C++语言的自然扩展。 TOracleDataSet ——该数据集组件支持Oracle记录锁定、记录刷新、服务器生成值、自动队列值生成、BLOB压缩。如果主表和从表之间存在外来关键字,或主表含有一个或多个列或属性(网表或varray),那么主从复合关系将自动建立。 TOracleDataSet可以在运行时使用Oracle字典内的信息,在客户端检查服务器约束,并在消息表中读取约束错误消息。能够从字典中获得格式屏蔽、区域值和默认值。这样,您所创建的应用程序将尽可能少的含有编译为可执行文件的数据库知识,还能够动态适应数据库的变化,无需重新编译。 支持Oracle专有特性 ——Direct Oracle Access支持许多Oracle专有特性。除了以上提及的特性之外,还支持Oracle 8和Oracle 8i特性,如LOB定位、对象和参考、XML TYPE、时间戳、滚动查询、密码到期、外部程序开发以及MTS Oracle服务等。 主要功能: 按范例查询模式 ——TOracleDataSet组件含有一个按范例查询模式,无需额外编程,也无需添加其他组件或控件,就能为您的程序提供QBE窗体。由于是在Oracle服务器上执行QBE查询,因此性能最优而且流量最低。用户能够提供简单的查询值,如JONES或100;能够包含字符串值通配符,如JON%;还包含比较操作符,如>, <, NOT, BETWEEN, IN等。 Oracle监控器 ——该组件能够监控您Direct Oracle Access程序的数据库访问行为。可以显示每个行为的SQL、变量、时间戳、逝去时间、网络统计表、数据库统计表和查询执行计划。这对于查找性能瓶颈非常有用,能够调整程序性能,解决程序错误。 警告和管道事件 ——Oracle Server为每个事件处理提供dbms_alert和dbms_pipe包。Direct Oracle Access中的TOracleEvent可以作为这些事件的接收器。TOracleEvent工作在您程序的后台线程中,可以向类似对象事件传播数据库事件。这些事件的发生可以同步或异步于您程序的主线程。 SQL脚本 ——如果需要执行多条数据定义语言(DDL)语句,例如运行您程序的数据库安装部分,就可以使用TOracleScript组件。该组件含有一个专有编辑器,可以开发脚本和单个命令。可扩展的脚本语言遵循基本的SQL*Plus语法,并支持所有SQL语句。除此,该语言还支持变量置换,从而令您的脚本可定制。 高级队列 ——TOracleQueue组件可以重发利用Oracle8的高级队列选项。该组件封装了DBMS_AQ包的基本功能。它提供了便利操作,能够将消息加入队列或者将其从队列中提取出来。消息提取操作是在您程序的后台线程中完成的,而线程模式中生成的事件可以同步或异步于您程序的主线程。 会话池 ——在服务器程序中,需要经常创建会话以处理来自客户端程序的请求,这对于连接池的使用非常有帮助。如果没有池的概念,那么每次请求都将引起数据库登录和离开行为。使用TOracleSessionPool组件后,您可以维护一个数据库会话池,能够被不同请求使用或重复使用。您可以定义池中会话的最大和最小数目,定义池中idle会话的TimeOut行为,并可以预先设置用户名、密码和数据库。

5,386

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧