放弃C++(Windows)中的处理器时间



我四处寻找了很多,似乎找不到我想要的东西,但让我首先强调,我不是在寻找高精度的睡眠功能。

以下是我试图解决的问题的背景:

我制作了一个内存映射库,它的操作非常像命名管道。您可以将字节放入其中,从中取出字节,并查询有多少字节可用于读/写,所有这些都很好。

它是快速的(大多数)进程,如果它们传递8KB或更大的字节块,使用它进行通信的平均速度将为4GB/s。当块大小接近512B时,性能会下降到300MB/s左右。

问题:

偶尔,在负载严重的服务器上,会出现非常大的滞后时间(5秒以上)。对于这个问题的原因,我的运行理论是,当发生大型传输(大于映射内存的大小)时,写入数据的进程将进行紧密轮询,以等待在内存映射顶部实现的循环缓冲区中有更多可用空间。没有睡眠调用,所以轮询过程可能毫无理由地占用CPU!问题是,即使是最小的睡眠时间(1毫秒)也绝对会破坏性能。内存映射大小为16KB,因此如果它每16KB睡眠1ms,性能将降至16MB/s的最佳情况。

解决方案:

我想要一个我可以调用的函数,它将放弃CPU,但不限制操作系统(在这种情况下是Windows 7)何时重新调度。

有人有什么好的选择吗/有人知道是否存在这样的函数吗?

谢谢。

根据MSDN文档,在XP或更新版本上,当您在超时为0的情况下调用Sleep时,将向其他具有同等优先级的进程让步。

值为零会导致线程放弃其剩余部分时间片到准备好跑如果没有其他具有同等优先级的线程准备运行函数立即返回,线程继续执行。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686298(v=vs.85).aspx

另一个需要更多工作但工作更可靠的选项是在生产者和消费者流程之间共享事件句柄。您可以使用CreateEvent创建您的事件,使用DuplicateHandle将其导入其他进程。当生产者填充缓冲区时,它将在事件句柄上调用ResetEvent,并用它调用WaitForSingleObject。当消费者从完全共享的缓冲区中删除了一些数据时,它将调用SetEvent,这将唤醒在WaitForSingleObject中等待的生产者。

std::this_thread::yield()可能会满足您的需求。我相信在大多数实现中,它只是用0调用Sleep。

您需要SwitchToThread()函数(如果其他程序可以运行,它将放弃其时间片),而不是Sleep(0)(即使其他程序无法运行,也将放弃其时间片)。

如果您正在编写旨在利用超线程的代码,YieldProcessor可能也会对您有所帮助,但我怀疑这是否有帮助。

您错误地假设了一个二进制选项。你现在总是忙于等待,因为睡觉总是个坏主意。

更好的解决办法是尝试几次而不睡觉。如果仍然失败(因为映射已满,而另一个线程没有运行),那么您可以发出真正的睡眠。这将是足够罕见的平均你将睡微秒。你甚至可以检查实时时钟(RDTSC),以确定在交出时间片之前你已经花了多长时间忙于等待。

如果您在.Net下操作,您可以查看Thread::Yield()方法。

它可能对您的特定场景有帮助,也可能没有帮助,但它是通知调度器您想要放弃剩余时间片的正确方式。

如果您在.Net之前的环境中运行(如果您在Windows7上,似乎不太可能),您可以转而研究Win32 SwitchToThread()函数。

相关内容

  • 没有找到相关文章

最新更新