spc_cll 发表于 2008-6-19 18:14:57

多线程方式顺序调用自定义函数线程类

/////////////////////////////////////////////////////////////////////////////////
/// 这是我在一个程序中编写多线程类,主要目的就是为了能够以多线程方式顺序调用自定义函数
/// 调用方式:1.TSynThread.Create(TFunction,false,'自定义消息');
///          2.TSynThread.Create(TObjFunction,false,'自定义消息');            
///          3.TSynThread.SaveMsg('自定义消息');
/// 请兄弟姐妹们多多指教。
///----------------------------------------------------------------------------------
/// 现在正在写一个用Excel服务器打印报表的程序,但遇到了CPU使用率很高的问题。
/// 明天把我的代码贴出来,希望对此有经验的兄弟姐妹们给予帮助。
/// 我的Email: [email protected]
/// 二○○八年六月十九日扬州
unit uSynThread;
interface
uses Classes,forms,SysUtils,inifiles,SyncObjs,uGVar;
type
TFunction = function:boolean;
TObjFunction = function:boolean of object;
TSynThread=Class(TThread)
private
    procedure CreateSelf(CreateSuspended: Boolean);
    procedure DoCallFun;
protected
    FSynNo:integer;
    FMsg:string;
    FCallFun:TFunction;
    FCallObjFun:TObjFunction;
    procedure Execute;override;
public
    constructor Create(CreateSuspended: Boolean);overload;
    constructor Create(Fun:TFunction;CreateSuspended:boolean;msg:String);overload;
    constructor Create(ObjFun:TObjFunction;CreateSuspended:boolean;msg:String);overload;
    Constructor SaveMsg(msg:string);
    destructor Destroy;override;
end;
var
SynThread:TSynThread;

procedure SaveErrMsg(ErrMsg:string);
implementation
var
CSynMsg:string='';
gSynNo:integer=0;
gSynCount:integer=0;
procedure SaveErrMsg(ErrMsg:string);
begin
with TIniFile.Create( ChangeFileExt( Application.ExeName, '.Err' )) do begin
    try
      WriteString('SYSTEM ERROR',DateTimetostr(now),ErrMsg);
    finally
      free;
    end;
end;
end;
{ TInitThread }
constructor TSynThread.Create(CreateSuspended: Boolean);
begin
CreateSelf(CreateSuspended);
end;
constructor TSynThread.Create(Fun: TFunction; CreateSuspended: boolean;msg:String);
begin
CreateSelf(CreateSuspended);
FMsg:=msg;
FCallFun:=Fun;
FCallObjFun:=nil;
end;
constructor TSynThread.Create(ObjFun: TObjFunction;
CreateSuspended: boolean; msg: String);
begin
CreateSelf(CreateSuspended);
FMsg:=msg;
FCallFun:=nil;
FCallObjFun:=ObjFun;
end;
procedure TSynThread.CreateSelf(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Priority := tpIdle;
FreeOnTerminate:=True;
FSynNo:=gSynCount;
gSynCount:=gSynCount+1;
end;
destructor TSynThread.Destroy;
begin
inherited;
end;
procedure TSynThread.DoCallFun;
begin
Try
    CSynMsg:=FMsg;
    if Assigned(FCallFun) then begin
       FCallFun();
    end;
    if Assigned(FCallObjFun) then begin
       FCallObjFun();
    end;
    if (not Assigned(FCallObjFun)) and (not Assigned(FCallFun)) then begin
       SaveErrMSG(FMsg);
    end;
except
    on E: Exception do begin
       SaveErrMSG(FMsg+'ErrCode='+inttostr(E.HelpContext)+':'+e.Message);      
    end;
end;
end;
procedure TSynThread.Execute;
begin
while not terminated do begin
    if FSynNo<=gSynNo then break;
    Application.ProcessMessages;
    sleep(10);
end;
/// 以上循环原本使用的是TEvent的,但我在使用时发生了一些意想不到的问题
/// 因此采用了这个结构来顺序调用程序。
Application.ProcessMessages;
Synchronize(DoCallFun);
SynThread:=nil;
gSynNo:=gSynNo+1;
end;
constructor TSynThread.SaveMsg(msg: string);
begin
CreateSelf(false);
FMsg:=msg;
FCallFun:=nil;
FCallObjFun:=nil;
end;
end.

caterpilla 发表于 2008-6-20 13:59:41

看了几遍,没太看明白/:002
楼主能否详细讲解下程序的目的?

spc_cll 发表于 2008-6-20 17:27:05

现谢谢惊涛【caterpilla】兄。

我现在编写的是一个数据实时采集并处理的程序。
在采集处理数据的同时,要自动或手动打印各种相关报表,有时还会向网络
发送相关数据。一般在处理外部设备时(如打印)都是耗时,耗CPU资源的。
因此编写了这个TSynThread线程类来处理各种需要延迟处理的事务。

其中有用Excel服务器打印报表的(采用Excel主要就是因为它设计表格方便,并用户可以很容易的设计自己需要的表格).
而在这个打印事务中,当链接到Excel文档(ConnectToBook函数)时,特别是第一次链接时,CPU使用率很高,甚至
长时间(2秒)达到100%,使系统有明显停顿的感觉,而且影响系统对数据的实时处理。

现在就是要想个办法来降低CPU的使用率.

参考例程【Excel打印测试】,这个例程是从原始程序中剥离出来的可独立运行。

suiyunonghen 发表于 2008-6-21 21:39:02

呵呵,使用过这种方法,不过我没有如你一样封装起来!我那个是语音报价的,使用线程报价,同时处理界面上的函数或事件。因为这样封装了之后似乎缺乏灵活性质了。现在Delphi版似乎人气不足大,希望楼主多发强贴振兴起来/:018

caterpilla 发表于 2008-6-24 16:15:24

原帖由 spc_cll 于 2008-6-20 17:27 发表 https://www.chinapyg.com/images/common/back.gif
现谢谢惊涛【caterpilla】兄。

我现在编写的是一个数据实时采集并处理的程序。
在采集处理数据的同时,要自动或手动打印各种相关报表,有时还会向网络
发送相关数据。一般在处理外部设备时(如打印)都是耗时, ...
谢谢说明!!!感觉明白了串行执行函数的意义。spc_cll兄不是为了用多线程并行工作,而是为了让线程来承担函数调用所带来的延时,通过EXCUTE中的WHILE循环内IF比较来限制线程执行的顺序,这样可以不影响主线程的执行。这样理解对吗?不过对于这个SynThread:TSynThread变量还不太了解,尤其是SynThread:=nil;这句,此为何意???此变量有何用处?另外那些全局变量在更改时是否应有同步操作?

spc_cll 发表于 2008-6-25 09:06:43

原帖由 caterpilla 于 2008-6-24 16:15 发表 https://www.chinapyg.com/images/common/back.gif

谢谢说明!!!感觉明白了串行执行函数的意义。spc_cll兄不是为了用多线程并行工作,而是为了让线程来承担函数调用所带来的延时,通过EXCUTE中的WHILE循环内IF比较来限制线程执行的顺序,这样可以不影响主线程的执 ...

是的,当初在EXCUTE中加入WHILE循环就是为了限制线程执行的顺序,若去掉该循环,那就是真的多线程了。
对于SynThread:TSynThread这个变量,定义它的目的是为了在程序其他地方可以方便的知道现在在执行哪一个线程以及该线程的相关信息。但这需要在Execute的While循环结束的地方加入下面这条语句:
   SynThread:=self;
变量CSynMsg,gSynNo,gSynCount定义在implementation之后,在其他单元是不可见的(也就是说,这些变量在其他引用本单元的地方并不是全局的变量.

愿caterpilla兄帮我解答一下【用线程方式调用Excel服务器打印自定义表格】中所提到的问题,可以吗?

[ 本帖最后由 spc_cll 于 2008-6-25 09:18 编辑 ]

caterpilla 发表于 2008-6-25 09:31:26

原帖由 spc_cll 于 2008-6-25 09:06 发表 https://www.chinapyg.com/images/common/back.gif


是的,当初在EXCUTE中加入WHILE循环就是为了限制线程执行的顺序,若去掉该循环,那就是真的多线程了。
对于SynThread:TSynThread这个变量,定义它的目的是为了在程序其他地方可以方便的知道现在在执行哪一个线程 ...
这些变量对于所有创建的线程不是共用的吗?线程间不存在同步的问题?

suiyunonghen 发表于 2008-6-27 11:32:43

在线程中使用TWebBrowser,不知道楼主使用过没有 !
似乎不能正常的进行操作
后来,我在线程中布置了一个窗体,然后将TWebBrowser放在了窗体上,窗体如果Visible为False的话,也不能正常操作,后来我将窗体隐藏在桌面之外,然后 方可操作!现在又碰到一个问题,就是似乎线程中的窗体的消息还是挂到了主线程中,导致在线程中使用
while Web.Busy or Web.ReadyState<>4 do
begin
end;
这样的循环出现界面死掉。按理说跑在子线程中的东西应该不会出现这个情况的啊 。

spc_cll 发表于 2008-6-30 08:46:00

回复 7# 的帖子

我设置这个变量的目的是为了方便的查询现在正在执行的线程的相关信息,比如说FMsg的数据(类型中还没有定义直接读该属性的函数),并不改变这些数据。
而这些是否是有效的数据,只要判断SynThread是否等于nil就可以确定了。
页: [1]
查看完整版本: 多线程方式顺序调用自定义函数线程类