我已经为 C++ 开发了一个类似于 Java 的监视器对象,并进行了一些改进。主要的改进是不仅有一个用于锁定和解锁的自旋循环,还有一个用于等待事件的循环。在这种情况下,您不必锁定互斥体,而是在 wait_poll-function 上提供谓词,并且代码反复尝试锁定互斥体轮询,如果它可以锁定互斥体,则调用返回(或移动)对的谓词布尔型和结果类型。
等待内核中的信号量和/或事件对象 (Win32) 可以轻松地从 1.000 到 10.000 个时钟周期,即使调用立即返回,因为之前已设置信号量或事件。所以必须有一个与这个等待间隔有合理关系的旋转计数,fe 旋转内核中花费的最小间隔的十分之一。
使用我的监视器对象,我从 glibc 中获取了自旋计数重新计算算法。而且我也在使用暂停指令。但我发现在我的 CPU(TR 3900X)上,暂停指令太快了。平均约为 0.78ns。在 Intel-CPU 上,大约 30ns 更合理。
这是代码:
#include <iostream>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <immintrin.h>
using namespace std;
using namespace chrono;
int main( int argc, char **argv )
{
static uint64_t const PAUSE_ROUNDS = 1'000'000'000;
auto start = high_resolution_clock::now();
for( uint64_t i = PAUSE_ROUNDS; i; --i )
_mm_pause();
double ns = (int64_t)duration_cast<nanoseconds>( high_resolution_clock::now() - start ).count() / (double)PAUSE_ROUNDS;
cout << ns << endl;
}
为什么 AMD 采取了如此愚蠢的暂停时间?PAUSE 用于自旋等待循环,并且应该与高速缓存行内容翻转到不同核心并返回所需的时间非常匹配。