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