简体   繁体   English

了解多媒体定时器的奇怪行为

[英]Understanding the strange behavior of multimedia timer

I am using Multimedia timers in my application (C# .NET) to increase accuracy of my timer and to achieve 1 ms timer frequency.我在我的应用程序 (C# .NET) 中使用多媒体计时器来提高我的计时器的准确性并实现 1 ms 计时器频率。 My application had been working great so far until recently it started behaving strangely.到目前为止,我的应用程序一直运行良好,直到最近它开始出现奇怪的行为。 I am trying to understand what is wrong with my application.我试图了解我的应用程序有什么问题。 Below are the steps taken以下是采取的步骤

  1. timer frequency is set to 1 ms, callback is called on every 1ms定时器频率设置为 1 毫秒,每 1 毫秒调用一次回调
  2. there are 4 threads, each creating its own timer object.有 4 个线程,每个线程创建自己的计时器对象。 They all are set to call the callback after 1ms.它们都设置为在 1ms 后调用回调。 These are individual instances and not shared.这些是单独的实例,不共享。
  3. old piece of code execution time was about 0.3 ms.旧代码执行时间约为 0.3 毫秒。 This was working fine until next step.这在下一步之前工作正常。
  4. application code is changed.应用程序代码已更改。 Timer callback function now takes about 1.2 ms for execution.定时器回调函数现在需要大约 1.2 毫秒的执行时间。 This is clearly a problem.这显然是一个问题。 (I am going to work on optimizing the code later. But now I just want to understand the multimedia timer behavior) (稍后我将致力于优化代码。但现在我只想了解多媒体计时器的行为)
  5. only the 1st thread is calling the timer callback where as for other threads the call back is called only twice or thrice and after that the callback is never called.只有第一个线程正在调用计时器回调,而对于其他线程,回调仅被调用两次或三次,此后不再调用回调。
  6. Looks like for other threads, the timer even is missed (?) and it cannot catch up.看起来对于其他线程,计时器甚至错过了(?)并且无法赶上。 (Its missed for every interrupt). (每次中断都会错过)。

Could you please explain me the behavior of the timer objects.你能解释一下计时器对象的行为吗? Are all the threads actually pointing to same timer object since its a single process?由于它是单个进程,所有线程实际上都指向同一个计时器对象吗? Why are other threads not calling the timer callback?为什么其他线程不调用定时器回调?

The maximum resolution for the Multimedia timer is 1ms.多媒体定时器的最大分辨率为 1ms。 This causes the programmable interrupt controller (on the hardware) to fire every 1ms.这会导致可编程中断控制器(在硬件上)每 1 毫秒触发一次。 If you fire up 4 threads that all create timers which have 1ms timings that does not mean you will get events more than once per millisecond.如果您启动 4 个线程,它们都创建了具有 1 毫秒计时的计时器,这并不意味着您每毫秒将获得多次事件。

I encourage you to read the Why are the Multimedia Timer APIs (timeSetEvent) not as accurate as I would expect?我鼓励您阅读为什么多媒体计时器 API (timeSetEvent) 没有我预期的那么准确? blog post on MSDN. MSDN 上的博客文章。

Some quotes that are applicable here (emphasis mine):一些适用于此的引用(强调我的):

The MM Timer APIs allow the developer to reprogram the Programmable Interrupt Controller (PIC) on the machine. MM 定时器 API 允许开发人员重新编程机器上的可编程中断控制器 (PIC)。 You can specify the new timer resolution.您可以指定新的计时器分辨率。 Typically, we will set this to 1 millisecond.通常,我们会将其设置为 1 毫秒。 This is the maximum resolution of the timer.这是定时器的最大分辨率。 We can't get sub-millisecond accuracy.我们无法获得亚毫秒级的准确度。 The effect of this reprogramming of the PIC is to cause the OS to wake up more often.这种对 PIC 重新编程的效果是导致操作系统更频繁地唤醒。 This increases the chances that our application will be notified by the operating system at the time we specified.这增加了操作系统在我们指定的时间通知我们的应用程序的机会。 I say, “Increases the chances” because we still can't guarantee that we will actually receive the notification even though the OS work up when we told it.我说,“增加机会”是因为我们仍然不能保证我们真的会收到通知,即使操作系统在我们告诉它时工作。

And:并且:

Remember that the PIC is used to wake up the OS so that it can decide what thread should be run next.请记住,PIC 用于唤醒操作系统,以便它可以决定接下来应该运行哪个线程。 The OS uses some very complex rules to determine what thread gets to occupy the processor next.操作系统使用一些非常复杂的规则来确定接下来哪个线程占用处理器。 Two of the things that the OS looks at to determine if it should run a thread or not are thread priority and thread quantum.操作系统查看以确定是否应该运行线程的两件事是线程优先级和线程量子。

So, even if you put the resolution down to the maximum of 1ms, you are not guaranteed that your thread will be the one chosen to do its work.因此,即使您将分辨率降低到 1 毫秒的最大值,也不能保证您的线程将成为被选中执行其工作的线程。

I suppose that you use a system timer that runs callbacks on a single dedicated thread.我想你使用了一个在单个专用线程上运行回调的系统计时器。

Then you set the system interval to 1 ms.然后将系统间隔设置为 1 毫秒。 And before your change the callback takes 0.3 ms to complete, so the callbacks of the 4 threads take 4 * 0.3 = 1.2 ms to complete.在您更改之前,回调需要 0.3 毫秒才能完成,因此 4 个线程的回调需要 4 * 0.3 = 1.2 毫秒才能完成。 So they manage to complete on 1-2 time intervals, and can all start again after that.所以他们设法在 1-2 个时间间隔内完成,之后都可以重新开始。

But after your change each callback takes 1.2 ms itself.但是在您更改后,每个回调本身需要 1.2 毫秒。 So we have requests to run callbacks from the threads 2-4 and another request from thread 1 (because the time interval ran out).所以我们有从线程 2-4 运行回调的请求和来自线程 1 的另一个请求(因为时间间隔用完了)。 After that it depends on the timer used, which request it will serve.之后,它取决于使用的计时器,它将服务哪个请求。 It turns out, that the one from the first thread.事实证明,来自第一个线程的那个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM