Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 我如何赋予此时间关键型过程相对于其他线程的优先级?_Multithreading_Delphi - Fatal编程技术网

Multithreading 我如何赋予此时间关键型过程相对于其他线程的优先级?

Multithreading 我如何赋予此时间关键型过程相对于其他线程的优先级?,multithreading,delphi,Multithreading,Delphi,为了写一个MIDI音序器,我需要一个稳定的脉冲来调用一个计时例程,这个定时例程比程序中的任何东西都有绝对的优先级,更优先于计算机中的任何东西。我使用TimeSetEvent这样做: TimeSetEvent (FInterval, 0, TimerUpdate, uInt32 (Self), TIME_PERIODIC); 其中,TimerUpdate是一个回调,它以tpTimeCritical优先级恢复一个单独的线程,并调用一个例程(FOnTimer),在该例程中处理所有MIDI事件 pro

为了写一个MIDI音序器,我需要一个稳定的脉冲来调用一个计时例程,这个定时例程比程序中的任何东西都有绝对的优先级,更优先于计算机中的任何东西。我使用TimeSetEvent这样做:

TimeSetEvent (FInterval, 0, TimerUpdate, uInt32 (Self), TIME_PERIODIC);
其中,TimerUpdate是一个回调,它以tpTimeCritical优先级恢复一个单独的线程,并调用一个例程(FOnTimer),在该例程中处理所有MIDI事件

procedure TThreaded_Timer.Execute;
begin
   if Assigned (FOnTimer) then
   begin
      while not Terminated do
      begin
         FOnTimer (Self);
         if not Terminated then Suspend;
      end; // while
   end; // if
   Terminate;
end; // Execute //

虽然这种构造比我以前尝试过的一些东西要好得多,但它对某些事件仍然非常敏感。令我惊讶的是,每次显示提示时,它都会结巴。为什么一个简单的提示会导致时间关键型线程的中断?当然,我可以关掉它,但还有哪些令人讨厌的惊喜在等着我呢?

多媒体计时器的精确度不是很高。是一篇解释原因的文章

与其依赖计时器来唤醒线程,为什么不在线程本身内管理睡眠和唤醒时间呢

可能是这样的(在伪代码中,很抱歉我不懂Delphi):

如果线程被设置为关键优先级,那么这将使您非常接近您的目标间隔,假设您在每次迭代中所做的工作为您的其他线程和系统的其余部分留出时间来完成它们的工作


祝你好运。

将计时器设置为略短于要求的时间(例如,10毫秒)

计时器出现时,将线程优先级提高到“高于正常值”

计算等待和执行睡眠的剩余时间,间隔稍短(例如,减少1毫秒)

现在开始循环等待正确的时间。在每个循环中,至少执行一次asm暂停;结束;不将核心推送到100%使用率的指令

当时间发生时,将线程优先级降低到“正常”


我认为这是您在不编写设备驱动程序的情况下所能做的最好的事情。

使用专门为此设计的多媒体计时器。Delphi计时器非常糟糕,只在空闲时间才会引起注意。基于线程的计时器只有在该线程引起注意时才有用。MMTimer在内核级别运行,并提供了一个非常精确的回调。我们将其用于硬件排序自动化控制,这是非常好的

这里是我的单元,它实现了一个MMTimer,作为一个更易于使用的TTimer。使用“重复”使其成为单发或重复

unit UArtMMTimer;

interface

uses
  Classes,
  SysUtils,
  ExtCtrls,
  MMSystem;

type
  TArtMMTimer = class( TObject )
    constructor Create;
    destructor  Destroy; override;
  PRIVATE
    FHandle              : MMResult;
    FRepeat              : boolean;
    FIntervalMS          : integer;
    FOnTimer             : TNotifyEvent;
    FEnabled             : boolean;
    procedure   RemoveEvent;
    procedure   InstallEvent;
    procedure   DoOnCallback;
    procedure   SetEnabled( AState : boolean );
    procedure   SetIntervalMS( AValue : integer );
  PUBLIC
    property  Enabled : boolean
                read FEnabled
                write SetEnabled;
    property  OnTimer : TNotifyEvent
                read FOnTimer
                write FOnTimer;
    property  IntervalMS : integer
                read FIntervalMS
                write SetIntervalMS;
  end;



implementation

uses
  Windows;


// TArtMMTimer
// --------------------------------------------------------------------


procedure MMTCallBack(uTimerID, uMessage: UINT;
    dwUser, dw1, dw2: DWORD) stdcall;
var
  Timer : TArtMMTimer;
begin
  Timer := TArtMMTimer( dwUser );
  Timer.DoOnCallback;
end;



constructor TArtMMTimer.Create;
begin
  Inherited Create;
  FIntervalMS := 100;
  FRepeat     := True;
end;


destructor  TArtMMTimer.Destroy;
begin
  FOnTimer := nil;
  RemoveEvent;
  Inherited Destroy;
end;


procedure   TArtMMTimer.RemoveEvent;
begin
  If FHandle <> 0 then
    begin
    timeKillEvent( FHandle );
    FHandle := 0;
    end;

end;

procedure   TArtMMTimer.InstallEvent;
var
  iFlags : integer;
begin
  RemoveEvent;

  If FRepeat then
    iFlags := TIME_PERIODIC Or TIME_CALLBACK_FUNCTION
   else
    iFlags := TIME_CALLBACK_FUNCTION;

  FHandle := timeSetEvent(
    FIntervalMS,
    0,
    @MMTCallBack,
    DWord(Self),
    iFlags );
end;

procedure   TArtMMTimer.SetEnabled( AState : boolean );
begin
  If AState <> FEnabled then
    begin
    FEnabled := AState;
    If FEnabled then
      InstallEvent
     else
      RemoveEvent;
    end;
end;



procedure   TArtMMTimer.DoOnCallback;
var
  NowHRCount, WaitHRCount,IntervalHRCount : THRCount;
begin
  If Assigned( FOnTimer ) then
    FOnTimer( Self );
end;


procedure   TArtMMTimer.SetIntervalMS( AValue : integer );
begin
  If AValue <> FIntervalMS then
    begin
    FIntervalMS := AValue;
    If Enabled then
      begin
      Enabled := False;
      Enabled := True;
      end;
    end;
end;

// End TArtMMTimer
// --------------------------------------------------------------------










end.
单位UArtMMTimer;
接口
使用
班级,
SysUtils,
ExtCtrls,
彩信系统;
类型
TArtMMTimer=类(TObject)
构造函数创建;
毁灭者毁灭;推翻
私有的
FHandle:MMResult;
FRepeat:布尔型;
FIntervalMS:整数;
FOnTimer:TNotifyEvent;
FEnabled:布尔值;
程序移除;
程序事件;
DoOnCallback程序;
过程SetEnabled(状态:布尔值);
过程设置间隔(AValue:integer);
公开的
已启用属性:布尔值
阅读能力
写设置启用;
属性OnTimer:TNotifyEvent
阅读方梯末
写方梯末;
属性间隔:整数
读芬特瓦尔斯
写setintervals;
结束;
实施
使用
窗户;
//酒石计时器
// --------------------------------------------------------------------
程序MMTCallBack(uTimerID,u消息:UINT;
dwUser,dw1,dw2:DWORD)stdcall;
变量
定时器:TArtMMTimer;
开始
计时器:=TArtMMTimer(dwUser);
Timer.DoOnCallback;
结束;
构造函数TArtMMTimer.Create;
开始
继承创造;
FIntervalMS:=100;
FRepeat:=真;
结束;
析构函数计时器。销毁;
开始
方梯末:=零;
移除事件;
继承性破坏;
结束;
程序TArtMMTimer.RemoveEvent;
开始
如果FHandle为0,则
开始
timeKillEvent(FHandle);
FHandle:=0;
结束;
结束;
过程TArtMMTimer.InstallEvent;
变量
iFlags:整数;
开始
移除事件;
如果是FRepeat那么
iFlags:=时间\周期或时间\回调\函数
其他的
iFlags:=时间回调函数;
FHandle:=时间事件(
芬特瓦尔姆斯,
0,
@MMTCallBack,
德沃德(赛尔夫),
iFlags);
结束;
过程TArtMMTimer.SetEnabled(AState:boolean);
开始
如果阿斯塔特的话
开始
FEnabled:=阿斯塔特;
如果可以的话
安装事件
其他的
移除事件;
结束;
结束;
程序TArtMMTimer.DoOnCallback;
变量
NowHRCount、WaitHRCount、IntervalHRCount:THRCount;
开始
如果已分配(FOnTimer),则
方梯末(自我);
结束;
程序TArtMMTimer.SetIntervalMS(AValue:integer);
开始
如果AValue FIntervalMS那么
开始
FIntervalMS:=AValue;
如果启用,则
开始
已启用:=假;
已启用:=真;
结束;
结束;
结束;
//结束计时器
// --------------------------------------------------------------------
结束。

谢谢你的建议。为了测试它们,我开发了一个用于测试所建议的算法的程序。测试了四种算法

  • Simple(由Brian Frost编写)-使用多媒体计时器(TimeSetEvent),它调用执行定时任务的回调
  • 线程化(Brian Pedersen)-与simple一样,但回调是在单独的线程中调用的。线程接收可能的最高优先级(时间关键型)
  • 循环(Miguel)-在这个算法中,我们根本不信任计时器,而是自己编写一个。回调是在一个循环中执行的,在每次调用之后,我们检查距离下一个滴答声还有多少时间,并等待下一个必须发生。线程具有最高优先级。我用asm停顿;来自Gabr的结束建议是事件处理的一种快速方式
  • Fire&Forget(我自己)-多媒体计时器在每个滴答声中创建一个具有最高优先级的独立线程,为其分配回调并忘记i
    unit UArtMMTimer;
    
    interface
    
    uses
      Classes,
      SysUtils,
      ExtCtrls,
      MMSystem;
    
    type
      TArtMMTimer = class( TObject )
        constructor Create;
        destructor  Destroy; override;
      PRIVATE
        FHandle              : MMResult;
        FRepeat              : boolean;
        FIntervalMS          : integer;
        FOnTimer             : TNotifyEvent;
        FEnabled             : boolean;
        procedure   RemoveEvent;
        procedure   InstallEvent;
        procedure   DoOnCallback;
        procedure   SetEnabled( AState : boolean );
        procedure   SetIntervalMS( AValue : integer );
      PUBLIC
        property  Enabled : boolean
                    read FEnabled
                    write SetEnabled;
        property  OnTimer : TNotifyEvent
                    read FOnTimer
                    write FOnTimer;
        property  IntervalMS : integer
                    read FIntervalMS
                    write SetIntervalMS;
      end;
    
    
    
    implementation
    
    uses
      Windows;
    
    
    // TArtMMTimer
    // --------------------------------------------------------------------
    
    
    procedure MMTCallBack(uTimerID, uMessage: UINT;
        dwUser, dw1, dw2: DWORD) stdcall;
    var
      Timer : TArtMMTimer;
    begin
      Timer := TArtMMTimer( dwUser );
      Timer.DoOnCallback;
    end;
    
    
    
    constructor TArtMMTimer.Create;
    begin
      Inherited Create;
      FIntervalMS := 100;
      FRepeat     := True;
    end;
    
    
    destructor  TArtMMTimer.Destroy;
    begin
      FOnTimer := nil;
      RemoveEvent;
      Inherited Destroy;
    end;
    
    
    procedure   TArtMMTimer.RemoveEvent;
    begin
      If FHandle <> 0 then
        begin
        timeKillEvent( FHandle );
        FHandle := 0;
        end;
    
    end;
    
    procedure   TArtMMTimer.InstallEvent;
    var
      iFlags : integer;
    begin
      RemoveEvent;
    
      If FRepeat then
        iFlags := TIME_PERIODIC Or TIME_CALLBACK_FUNCTION
       else
        iFlags := TIME_CALLBACK_FUNCTION;
    
      FHandle := timeSetEvent(
        FIntervalMS,
        0,
        @MMTCallBack,
        DWord(Self),
        iFlags );
    end;
    
    procedure   TArtMMTimer.SetEnabled( AState : boolean );
    begin
      If AState <> FEnabled then
        begin
        FEnabled := AState;
        If FEnabled then
          InstallEvent
         else
          RemoveEvent;
        end;
    end;
    
    
    
    procedure   TArtMMTimer.DoOnCallback;
    var
      NowHRCount, WaitHRCount,IntervalHRCount : THRCount;
    begin
      If Assigned( FOnTimer ) then
        FOnTimer( Self );
    end;
    
    
    procedure   TArtMMTimer.SetIntervalMS( AValue : integer );
    begin
      If AValue <> FIntervalMS then
        begin
        FIntervalMS := AValue;
        If Enabled then
          begin
          Enabled := False;
          Enabled := True;
          end;
        end;
    end;
    
    // End TArtMMTimer
    // --------------------------------------------------------------------
    
    
    
    
    
    
    
    
    
    
    end.
    
                      Parameters                            Constancy of    Beat                Workload
    Timer              N Interval Resolution WorkLoad        Mean     s.d.     Min     Max    Mean    s.d.     Min     Max
    Simple           226       22         30     1000      22.001    0.001  21.996  22.009   0.093   0.036   0.079   0.302
    Threaded         226       22         30     1000      22.001    0.004  21.964  22.031   0.091   0.032   0.079   0.253
    Looping          227       22         30     1000      22.000    0.002  21.999  22.025   0.093   0.034   0.079   0.197
    Fire & Forget    226       22         30     1000      22.001    0.008  21.964  22.042   0.091   0.031   0.079   0.186
    Simple           226       22         15     1000      22.001    0.002  21.989  22.011   0.091   0.031   0.079   0.224
    Threaded         226       22         15     1000      22.001    0.003  21.978  22.031   0.091   0.032   0.079   0.185
    Looping          227       22         15     1000      22.000    0.001  21.999  22.015   0.092   0.034   0.079   0.209
    Fire & Forget    226       22         15     1000      22.001    0.015  21.861  22.146   0.091   0.031   0.079   0.173
    Simple           226       22          0     1000      22.001    0.001  21.997  22.005   0.091   0.030   0.079   0.190
    Threaded         226       22          0     1000      22.001    0.003  21.979  22.029   0.091   0.031   0.079   0.182
    Looping          227       22          0     1000      22.000    0.000  21.999  22.002   0.092   0.034   0.079   0.194
    Fire & Forget    226       22          0     1000      22.001    0.026  21.747  22.256   0.090   0.030   0.079   0.180
    Simple           226       22         30    10000      22.001    0.002  21.992  22.012   0.801   0.034   0.787   1.001
    Threaded         226       22         30    10000      22.001    0.002  21.994  22.008   0.800   0.031   0.787   0.898
    Looping          227       22         30    10000      22.000    0.000  21.999  22.000   0.802   0.034   0.787   0.919
    Fire & Forget    226       22         30    10000      22.001    0.010  21.952  22.087   0.903   0.230   0.788   1.551
    Simple           226       22         15    10000      22.001    0.002  21.984  22.020   0.810   0.081   0.788   1.417
    Threaded         226       22         15    10000      22.001    0.006  21.981  22.073   0.800   0.031   0.788   0.889
    Looping          227       22         15    10000      22.000    0.000  21.999  22.000   0.802   0.036   0.787   0.969
    Fire & Forget    226       22         15    10000      22.001    0.009  21.914  22.055   0.799   0.030   0.788   0.885
    Simple           226       22          0    10000      22.001    0.002  21.994  22.006   0.799   0.030   0.788   0.894
    Threaded         226       22          0    10000      22.001    0.005  21.953  22.048   0.799   0.030   0.787   0.890
    Looping          227       22          0    10000      22.000    0.000  21.999  22.002   0.801   0.034   0.787   0.954
    Fire & Forget    226       22          0    10000      22.001    0.007  21.977  22.029   0.799   0.030   0.788   0.891
    Simple           226       22         30   100000      22.001    0.002  21.988  22.017   7.900   0.052   7.879   8.289
    Threaded         226       22         30   100000      22.001    0.003  21.967  22.035   7.897   0.036   7.879   8.185
    Looping          227       22         30   100000      22.000    0.001  21.999  22.015   7.908   0.098   7.879   9.165
    Fire & Forget    225       22         30   100000      22.001    0.007  21.960  22.027   7.901   0.038   7.880   8.061
    Simple           227       22         15   100000      22.014    0.195  21.996  24.934   7.902   0.056   7.879   8.351
    Threaded         226       22         15   100000      22.001    0.002  21.997  22.008   7.900   0.049   7.879   8.362
    Looping          227       22         15   100000      22.000    0.000  22.000  22.000   7.900   0.046   7.879   8.229
    Fire & Forget    225       22         15   100000      22.001    0.008  21.962  22.065   7.906   0.082   7.880   8.891
    Simple           227       22          0   100000      22.018    0.261  21.937  25.936   7.901   0.050   7.879   8.239
    Threaded         226       22          0   100000      22.001    0.001  21.998  22.005   7.897   0.031   7.879   7.987
    Looping          227       22          0   100000      22.000    0.000  21.999  22.000   7.901   0.053   7.879   8.263
    Fire & Forget    225       22          0   100000      22.001    0.007  21.967  22.032   7.900   0.044   7.880   8.308
    Simple            63       22         30  1000000      78.027    6.801  24.938  80.730  77.754   8.947   7.890  80.726
    Threaded          56       22         30  1000000      87.908    1.334  78.832  91.787  78.897   0.219  78.819  80.430
    Looping           62       22         30  1000000      78.923    0.320  78.808  80.749  78.923   0.320  78.808  80.748
    Fire & Forget    222       22         30  1000000      22.001    0.009  21.956  22.038  84.212   3.431  78.825  91.812
    Simple            66       22         15  1000000      75.656   13.090  21.994  80.714  79.183   1.559  78.811  90.950
    Threaded          56       22         15  1000000      87.841    1.204  78.991  88.011  78.849   0.043  78.812  79.003
    Looping           62       22         15  1000000      78.880    0.207  78.807  80.442  78.880   0.207  78.807  80.441
    Fire & Forget    222       22         15  1000000      22.001    0.978  11.975  32.042  84.915   3.569  78.816  90.917
    Simple            66       22          0  1000000      75.681   12.992  21.991  80.778  79.213   1.400  78.807  87.766
    Threaded          56       22          0  1000000      87.868    1.238  78.889  89.515  78.954   0.597  78.813  83.164
    Looping           62       22          0  1000000      78.942    0.307  78.806  80.380  78.942   0.307  78.806  80.379
    Fire & Forget    222       22          0  1000000      22.001    0.011  21.926  22.076  83.953   3.103  78.821  91.145