gpt4 book ai didi

c++ - 信号量延迟比预期更快 - 为什么?

转载 作者:行者123 更新时间:2023-12-04 14:01:33 26 4
gpt4 key购买 nike

信号量的获取是通过阻塞完成的。根据互联网和时钟,Windows 上的中断频率/定时器间隔不应低于 0.5 毫秒。下面的程序测量不同线程中信号量的释放和获取之间的时间。我不希望这比 0.5ms 快,但我可靠地得到了 ~0.017ms 的结果。 (奇怪的是具有 +- 100% 的高标准偏差)
要么我的测量代码是错误的,要么我对信号量工作方式的理解是错误的。是哪个?没有无聊代码的代码来计算平均值和标准偏差:

namespace {
std::binary_semaphore semaphore{ 0 };
std::atomic<std::chrono::high_resolution_clock::time_point> t1;
}

auto acquire_and_set_t1() {
semaphore.acquire(); // this is being measured
t1.store(std::chrono::high_resolution_clock::now());
}

auto measure_semaphore_latency() -> double {
std::jthread j(acquire_and_set_t1);
std::this_thread::sleep_for(5ms); // To make sure thread is running

// Signal thread and start timing
const auto t0 = std::chrono::high_resolution_clock::now();
semaphore.release();

std::this_thread::sleep_for(5ms); // To make sure thread is done writing t1

const double ms = std::chrono::duration_cast<std::chrono::nanoseconds>(t1.load() - t0).count() / 1'000'000.0;
return ms;
}

auto main() -> int {
std::vector<double> runtimes;
for (int i = 0; i < 100; ++i)
runtimes.emplace_back(measure_semaphore_latency());

const auto& [mean, relative_std] = get_mean_and_std(runtimes);
std::cout << std::format("mean: {:.3f} ms, +- {:.2f}%\n", mean, 100.0 * relative_std);
}
编辑:Windows 计时器分辨率的来源是 https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/ClockRes

最佳答案

您的困惑来自错误的假设,即这会起作用:

According to the internet and clockres, the interrupt frequency / timer interval on Windows shouldn't be under 0.5ms.


抢占式/基于定时器的调度不一定是操作系统将线程分配给 CPU 内核的唯一机会。显式/手动信令可以绕过它。
你可以把它想象成 std::binary_semaphore::release()触发调度程序的立即部分运行,仅针对碰巧具有 std::binary_semaphore::acquire() 的线程在同一个信号量上。
这就是这里发生的事情。 measure_semaphore_latency()线程正在被唤醒并可能立即分配给 CPU 内核,因为 release()进行调用,无需等待下一个调度“周期”。
仍然不能保证操作系统会选择抢占那个刚刚唤醒的线程的任何东西。这就是您所看到的高标准偏差的来源:线程要么立即获得 CPU 时间,要么在稍后的调度周期中获得,没有中间时间。
至于为什么我可以如此确信您的测试就是这种情况:通过一些调试和符号加载,我们可以获得以下调用堆栈:
在收购方面:
    ntdll.dll!00007fffa4510764()    Unknown
ntdll.dll!00007fffa44d379d() Unknown
ntdll.dll!00007fffa44d3652() Unknown
ntdll.dll!00007fffa44d3363() Unknown
KernelBase.dll!00007fffa225ce9f() Unknown
> msvcp140d_atomic_wait.dll!`anonymous namespace'::__crtWaitOnAddress(volatile void * Address, void * CompareAddress, unsigned __int64 AddressSize, unsigned long dwMilliseconds) Line 174 C++
msvcp140d_atomic_wait.dll!__std_atomic_wait_direct(const void * _Storage, void * _Comparand, unsigned __int64 _Size, unsigned long _Remaining_timeout) Line 234 C++
ConsoleApplication2.exe!std::_Atomic_wait_direct<unsigned char,char>(const std::_Atomic_storage<unsigned char,1> * const _This, char _Expected_bytes, const std::memory_order _Order) Line 491 C++
ConsoleApplication2.exe!std::_Atomic_storage<unsigned char,1>::wait(const unsigned char _Expected, const std::memory_order _Order) Line 829 C++
ConsoleApplication2.exe!std::counting_semaphore<1>::acquire() Line 245 C++
ConsoleApplication2.exe!acquire_and_set_t1() Line 17 C++
ConsoleApplication2.exe!std::invoke<void (__cdecl*)(void)>(void(*)() && _Obj) Line 1586 C++
ConsoleApplication2.exe!std::thread::_Invoke<std::tuple<void (__cdecl*)(void)>,0>(void * _RawVals) Line 56 C++
ucrtbased.dll!00007fff4c7b542c() Unknown
kernel32.dll!00007fffa2857034() Unknown
ntdll.dll!00007fffa44c2651() Unknown

在发布方面:
    ntdll.dll!00007fffa44d2550()    Unknown 
> msvcp140d_atomic_wait.dll!`anonymous namespace'::__crtWakeByAddressSingle(void * Address) Line 179 C++
msvcp140d_atomic_wait.dll!__std_atomic_notify_one_direct(const void * _Storage) Line 251 C++
ConsoleApplication2.exe!std::_Atomic_storage<unsigned char,1>::notify_one() Line 833 C++
ConsoleApplication2.exe!std::counting_semaphore<1>::release(const __int64 _Update) Line 232 C++
ConsoleApplication2.exe!measure_semaphore_latency() Line 29 C++
ConsoleApplication2.exe!main() Line 36 C++
ConsoleApplication2.exe!invoke_main() Line 79 C++
ConsoleApplication2.exe!__scrt_common_main_seh() Line 288 C++
ConsoleApplication2.exe!__scrt_common_main() Line 331 C++
ConsoleApplication2.exe!mainCRTStartup(void * __formal) Line 17 C++
kernel32.dll!00007fffa2857034() Unknown
ntdll.dll!00007fffa44c2651() Unknown
浏览 __crtWakeByAddressSingle() 的代码, 和 __crtWaitOnAddress() (see on github)我们发现调用的核函数是 WaitOnAddress() refWakeByAddressSingle() ref .
从本文档中,我们可以在 WaitOnAddress() 的备注部分找到我们的确认信息。 :

WaitOnAddress does not interfere with the thread scheduler.

关于c++ - 信号量延迟比预期更快 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69913808/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com