WaitOnAddress
是从Windows 8开始的理想工具。我暂时必须支持Windows 7,我发现的最好的改进(包括搜索和阅读MSDN)超过Win32 API 事件与 SleepConditionVariableCS
一起使用。
这是一个最小的示例(在控制台应用程序中处理 Ctrl-C):
//HANDLE Signal; // event
CONDITION_VARIABLE Signal;
CRITICAL_SECTION cs;
BOOL WINAPI CtrlHandler(DWORD ctl){
switch (ctl) {
case CTRL_C_EVENT: /*SetEvent(Signal);*/ WakeConditionVariable(&Signal); return TRUE;
default: return FALSE; // pass it to the system
}
}
int main(){
//Signal = CreateEventA(NULL, TRUE /*manual-reset event*/,
// FALSE/*initial nonsignaled*/, "ctrl-c_sig023xgyI8");
InitializeConditionVariable(&Signal); InitializeCriticalSection(&cs);
SetConsoleCtrlHandler(CtrlHandler, TRUE) // register CtrlHandler with the system
// auto hThread = CreateThread(nullptr, 0, worker, nullptr, ..);
//WaitForSingleObject(Signal, INFINITE);
EnterCriticalSection(&cs);
SleepConditionVariableCS (&Signal, &cs, INFINITE);
LeaveCriticalSection(&cs);
// stop thread, cleanup, CloseHandle(hThread); CloseHandle(Signal);
return 0;
}
此示例强制使用“信号”用例:系统启动一个专用线程只是为了运行您的
CtrlHandler
(当用户输入Ctrl-C时),然后它有机会向用户发出信号main
线程-请求停止。
Win32 API 或 C++ 中是否有更好(更轻量)的方法(当然,C++ 最终必须通过 Win32 API)。
看起来没有比
SleepConditionVariableCS/SRW
更快的了。
这些之间没有太大区别。这在我的 CPU 上显示出
SRW
(~2%) 的轻微优势:
int main(int argc, char **argv){
CONDITION_VARIABLE cv; InitializeConditionVariable(&cv);
//SRWLOCK Signal; InitializeSRWLock(&Signal);
CRITICAL_SECTION cs; InitializeCriticalSection(&cs);
//std::mutex mtx;
//std::condition_variable ccv;
bool stop_thread = false;
auto th1 = std::thread([&](){ while(true){ WakeConditionVariable(&cv); if(stop_thread) return; }});
//auto th1 = std::thread([&](){ while(true){ ccv.notify_one(); if(stop_thread) return; }});
const int64_t n = 1000 * 1000 * 1000;
auto start = std::chrono::high_resolution_clock::now();
for (int64_t i = 0; i < n; i++) {
//AcquireSRWLockExclusive(&Signal);
// SleepConditionVariableSRW(&cv, &Signal, INFINITE, 0);
//ReleaseSRWLockExclusive(&Signal);
EnterCriticalSection(&cs);
SleepConditionVariableCS (&cv, &cs, INFINITE);
LeaveCriticalSection(&cs);
//std::unique_lock lk(mtx);
//ccv.wait(lk);
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
stop_thread = true; th1.join();
double nSec = 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
printf("%.3lf calls/sec\n", n / nSec);
return 0;
}
std::condition_variable
慢了 20%。
底线:如果你不需要递归/你的争用程度较低(没有
Try..
的恶作剧 SRW
),请使用 SRW
(使用 NtCreateKeyedEvent 特殊酱汁),否则使用 CS
。