【问题标题】:Millisecond-Accurate Scheduling of Future Events in C++/CLIC++/CLI 中未来事件的毫秒级精确调度
【发布时间】:2010-06-05 04:17:40
【问题描述】:

我需要创建一个 C++/CLI 混合程序集,该程序集可以将未来的调用安排到本机 DLL 中,精确到毫秒。

当然,这意味着提前设置一个计时器(什么类型的?)一到三毫秒,然后一直旋转到这一刻并调用本机 DLL 函数。

根据我读到的内容,我猜想定时器调用的回调需要是原生的,以确保没有 thunk 或 GC 来延迟处理定时器回调。

整个线程或进程是否需要是本机和无 CLR 的,或者这可以通过 #pragma unmanaged 或将程序集的一个文件设置为本机编译一样准确地完成吗?

如果有,怎么做?

如果确实无法在混合模式 C++/CLI 中执行此操作,那么设置应用程序/线程(即 DLL 或 exe?)来处理它并取回数据的最简单方法是什么在本机和托管线程/应用程序之间来回切换?

【问题讨论】:

  • 有结构体、联合体、帕斯卡字符串、任意长度的缓冲区等来回传递给专有的本机 DLL,因此需要在临界区之外进行一些重组为更健全的数据类型(s) 在 C++/CLI 或本机 C++ 中尝试使用 .NET 军事 API。
  • 我希望它能让我也添加“windows”和“callback”作为标签。 (其他建议?)
  • 您知道,在抢占式多任务操作系统上,无论线程是在运行本机代码还是托管代码,您都无法保证代码在回调触发之前不会被中断。
  • JS Bangs 的陈述总体上是完全错误的,并且在 Windows 上大多是错误的。在许多抢先式多任务操作系统上,线程永远不会被较低优先级的线程中断(由于中断处理导致的延迟比 1 毫秒快得多)。在 Windows 上,如果内核检测到优先级反转的迹象,那么它会临时随机更改优先级以恢复,但如果您使用实时优先级,您的线程应该仍然不受此影响。
  • 谢谢你,本。还有其他人对我有一些实施最佳实践吗?我还不知道从 .NET Winforms GUI 控制时有什么方法可以实现这一点。如何让 .NET 完全避开响应 1 毫秒早期计时器、旋转到正确的微秒并进行本机 DLL 调用的部分?我如何 IPC/互操作到该 Native 位?请提供最佳实践。 :)

标签: .net multithreading interop c++-cli timer


【解决方案1】:

您确实需要整个线程都没有 CLR。一旦任何托管代码在线程上运行,它就会被添加到 CLR 的线程列表中以在收集期间挂起。

不过,您的最后一个问题表明您对多线程一无所知。线程和 DLL 之间没有对应关系。一个 DLL 可以有许多线程,每个线程都可以运行来自许多 DLL 的代码(事实上,如果算上 Windows DLL,总是这样)。您也没有以通常的方式使用“关键部分”这个短语。

混合模式 C++/CLI 程序集可以包含纯本机线程(使用本机 CreateThread 调用启动它,传递本机线程过程,并且不要从该线程直接或间接调用任何托管代码)。如果您将本机线程的代码编写在一个或多个设置为在不使用 /clr 的情况下进行编译的文件中,您的生活会轻松一些,托管代码不可见可以更容易地避免调用它,但要注意可能会包装的函数指针托管委托。

除此之外,使用无锁同步,例如SList,或者您的本机线程最终可能会等待在已暂停垃圾回收的混合模式线程上持有的锁。除此之外,这意味着不使用任何标准共享分配器,因为它们在内部使用锁定。不过确实存在一些无锁分配器。

编辑:包装托管委托的函数指针是通过调用Marshal::GetDelegateForFunctionPointer 创建的。之后,它们就像指向本机函数的指针一样(可以将它们区分开来),并且在这样的指针上使用函数调用运算符将​​导致托管代码在敏感线程上运行。在大多数情况下,这不会是一个问题,只要确保您使用委托作为一种快捷方式来产生对托管代码的回调,您是从混合线程中执行此操作的,而不是您打算仅作为本机的线程。

一般来说,您可能需要某种纯粹的本地消息传递方案来交换数据。混合线程可以进行任何必要的本机调用,您可以在所有其他线程上混合本机代码和托管代码,只保留一个对时间敏感的本地代码。

所有的thunking都应该发生在混合线程上,它不会延迟时间敏感的本机线程,除非混合线程持有本机线程需要的锁。因此我建议使用非锁定数据交换。

【讨论】:

  • 所以可以在混合程序集中使线程无 CLR,并且该线程可以不受托管/混合线程的抑制? (寻找其他人同意或不同意,并进一步解释。)是否有自动“包装托管委托的函数指针”?如何避免意外使用它们?我知道 DLL 映射为加载程序的一部分,并且线程可以使用来自许多 DLL 的代码。问题是最佳实践:是为此创建一个进程(如果是,如何最好地对其进行 IPC)还是创建一个纯本机线程(以及如何编写对它的调用)。
  • 我担心如何在时间敏感的时刻将线程或 IPC 互操作到进程中而不会出现重击。 (很抱歉,当我不是指锁争用时,将其称为关键部分。)
【解决方案2】:

它根本不能在 Windows 中完成 - 抱歉。获取符合您要求的操作系统。

  • Windows 中的普通计时器具有 10 毫秒的精度。
  • 即使您让它与高性能计时器一起使用,Windows 中也无法保证调用将在特定时间内得到兑现 - 您的 1 毫秒调用可能会延迟 5 毫秒。

您需要/似乎需要的是实时操作系统。

【讨论】:

  • 此硬件只有 Windows 驱动程序。在本机 Windows 领域,您可以获得 99.99% 的可靠性(比我需要的更好),精度为 1ms。到处都有例子。当我整天使用计算机时,我已经运行了一个并获得了零故障。问题是关于如何在不让 .NET 妨碍关键部分的情况下将其引入 .NET。我想知道如何编写回调,以便在计时器关闭和调用 DLL 之间不会发生 thunk 或 GC。
  • 还是不走运。对于 GC - 设置非阻塞 GC。除此之外,我不知道 .NET 会影响您的方式。
猜你喜欢
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-23
  • 2014-03-20
  • 2015-09-13
相关资源
最近更新 更多