飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 4500|回复: 8

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

[复制链接]
  • TA的每日心情
    擦汗
    2020-7-7 10:06
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 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.

    uSynThread.rar

    1.45 KB, 下载次数: 5, 下载积分: 飘云币 -2 枚

    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-6-20 13:59:41 | 显示全部楼层
    看了几遍,没太看明白/:002
    楼主能否详细讲解下程序的目的?
    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2020-7-7 10:06
  • 签到天数: 2 天

    [LV.1]初来乍到

     楼主| 发表于 2008-6-20 17:27:05 | 显示全部楼层
    现谢谢惊涛【caterpilla】兄。

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

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

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

    参考例程【Excel打印测试】,这个例程是从原始程序中剥离出来的可独立运行。
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2017-4-20 22:12
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2008-6-21 21:39:02 | 显示全部楼层
    呵呵,使用过这种方法,不过我没有如你一样封装起来!我那个是语音报价的,使用线程报价,同时处理界面上的函数或事件。因为这样封装了之后似乎缺乏灵活性质了。现在Delphi版似乎人气不足大,希望楼主多发强贴振兴起来/:018
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-6-24 16:15:24 | 显示全部楼层
    原帖由 spc_cll 于 2008-6-20 17:27 发表
    现谢谢惊涛【caterpilla】兄。

    我现在编写的是一个数据实时采集并处理的程序。
    在采集处理数据的同时,要自动或手动打印各种相关报表,有时还会向网络
    发送相关数据。一般在处理外部设备时(如打印)都是耗时, ...

    谢谢说明!!!感觉明白了串行执行函数的意义。spc_cll兄不是为了用多线程并行工作,而是为了让线程来承担函数调用所带来的延时,通过EXCUTE中的WHILE循环内IF比较来限制线程执行的顺序,这样可以不影响主线程的执行。这样理解对吗?不过对于这个SynThread:TSynThread变量还不太了解,尤其是SynThread:=nil;这句,此为何意???此变量有何用处?另外那些全局变量在更改时是否应有同步操作?
    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2020-7-7 10:06
  • 签到天数: 2 天

    [LV.1]初来乍到

     楼主| 发表于 2008-6-25 09:06:43 | 显示全部楼层
    原帖由 caterpilla 于 2008-6-24 16:15 发表

    谢谢说明!!!感觉明白了串行执行函数的意义。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 编辑 ]
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-6-25 09:31:26 | 显示全部楼层
    原帖由 spc_cll 于 2008-6-25 09:06 发表


    是的,当初在EXCUTE中加入WHILE循环就是为了限制线程执行的顺序,若去掉该循环,那就是真的多线程了。
    对于SynThread:TSynThread这个变量,定义它的目的是为了在程序其他地方可以方便的知道现在在执行哪一个线程 ...

    这些变量对于所有创建的线程不是共用的吗?线程间不存在同步的问题?
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2017-4-20 22:12
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2008-6-27 11:32:43 | 显示全部楼层
    在线程中使用TWebBrowser,不知道楼主使用过没有 !
    似乎不能正常的进行操作
    后来,我在线程中布置了一个窗体,然后将TWebBrowser放在了窗体上,窗体如果Visible为False的话,也不能正常操作,后来我将窗体隐藏在桌面之外,然后 方可操作!现在又碰到一个问题,就是似乎线程中的窗体的消息还是挂到了主线程中,导致在线程中使用
    while Web.Busy or Web.ReadyState<>4 do
    begin
    end;
    这样的循环出现界面死掉。按理说跑在子线程中的东西应该不会出现这个情况的啊 。
    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2020-7-7 10:06
  • 签到天数: 2 天

    [LV.1]初来乍到

     楼主| 发表于 2008-6-30 08:46:00 | 显示全部楼层

    回复 7# 的帖子

    我设置这个变量的目的是为了方便的查询现在正在执行的线程的相关信息,比如说FMsg的数据(类型中还没有定义直接读该属性的函数),并不改变这些数据。
    而这些是否是有效的数据,只要判断SynThread是否等于nil就可以确定了。
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表