独立于架构的自旋等待循环

为了充分利用当今多核处理器的功能,游戏开发人员正使用更高级的任务处理系统使工作分散到线程池的多个线程之中。随着线程数量的增加,诸如任务队列锁和其他共享资源结构上的线程之间发生争用的可能性也会增加。有多种解决办法,但是自旋等待循环是常见的结构。

while (!acquire_lock())
{
	// Spin for a specific number of iterations
	for (int i = 0; i < max_spin_count; i++)
	{
		// Pause intrinsic
		_mm_pause();
	}
}

本文使用了 The _mm_pause 指令,因为它可以提示处理器调用线程位于自选等待循环中。这将暂停下一条指令的执行,不再需要处理器,也不会使用部分管线,因此降低了能耗。

_mm_pause 指令在多数前几代英特尔平台上拥有相似的延迟。由于存在这种历史一致性,许多开发人员在调整自旋循环时会考虑到这一点。但是,从第六代智能英特尔® 酷睿™ i 处理器产品家族开始,pause 指令的延迟增加了多个数量级,旨在为许多场景提供更好的节能机会。

由于延迟发生了变化,以上固定数量的自旋循环将消耗比之前高一个数量级的周期,这将对您的应用性能造成不利影响。为了避免未来的指令架构变动引起任何问题,对所有自旋等待循环进行检查,以确保未使用固定数量的 pause 指令实施它们。可以对上述自旋等待循环进行以下适当修改:

while (!acquire_lock())
{
	// __rdtsc intrinsic is used to read the time stamp counter
	// This allows the loop to run for a fixed number of cycles
	uint64_t prev = __rdtsc();
	do
	{
		// Pause intrinsic

		_mm_pause();
	}
	while ((__rdtsc() - prev) < max_spin_time)
	}

尽管上述自旋等待循环非常简单,软件开发人员一般会使用更高级的自旋循环(支持指数退避等),但是它展示了如何使软件变得更强大,以应对未来指令延迟的架构变动。

 

请参阅以下文章,进一步了解 _mm_pause 指令与自旋等待循环:有益于功耗与性能的睡眠循环

如欲获取关于英特尔® 架构编程的更多信息,请参阅以下软件开发手册:《64 位和 32 位英特尔®架构软件开发人员手册》

有关编译器优化的更完整信息,请参阅优化通知