先分清 Sleep、sleep 和 sleep_for
跳转到“先分清 Sleep、sleep 和 sleep_for”原记录在 move_kinova.cpp 中遇到 C3861“找不到标识符”,标题写 Sleep,正文却混用了 sleep。C++ 标识符区分大小写;Windows API 的名称是 Sleep。包含 Windows SDK 头文件可以提供它的声明,但不会把小写 sleep 变成同一个函数。
| 接口 | 环境与头文件 | 参数含义 |
|---|---|---|
Sleep(20) | Windows API,通常包含 <windows.h> | 当前线程等待约 20 毫秒,实际调度有误差 |
sleep(1) | POSIX,<unistd.h> | 以秒为单位,可被信号打断并返回未睡完的秒数 |
std::this_thread::sleep_for(std::chrono::milliseconds(20)) | C++11 起,<thread> 与 <chrono> | 使用明确的时长类型阻塞当前线程 |
POSIX sleep 的中断与返回值语义见 POSIX sleep。
找不到声明时先检查名称、头文件、当前平台和 SDK。若源码已编译成目标文件,后来报告未解析的外部符号,那是链接问题,需要另查库依赖。Sleep 的 Windows 文档列出 Kernel32.lib;普通 Windows 工具链通常已默认处理这个基础依赖。Microsoft Sleep 文档
可移植等待与 Windows 分支
跳转到“可移植等待与 Windows 分支”下面保存为 sleep_demo.cpp。标准等待使用 steady_clock 记录经过时间;Windows 分支另外调用一次 Sleep,其他系统不会编译这段代码。
#include <cassert>#include <chrono>#include <iostream>#include <thread>
#ifdef _WIN32#ifndef WIN32_LEAN_AND_MEAN#define WIN32_LEAN_AND_MEAN#endif#ifndef NOMINMAX#define NOMINMAX#endif#include <windows.h>#endif
int main(){ using Clock = std::chrono::steady_clock; const auto requested = std::chrono::milliseconds(20); const auto begin = Clock::now(); std::this_thread::sleep_for(requested); const auto elapsed = Clock::now() - begin; assert(elapsed >= requested); std::cout << "sleep_for elapsed us: " << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() << '\n';
#ifdef _WIN32 Sleep(20); std::cout << "Windows Sleep returned\n";#endif}GCC/MinGW 可使用 g++ -std=c++17 sleep_demo.cpp -o sleep_demo -pthread;Windows PowerShell 运行 ./sleep_demo.exe,Linux shell 运行 ./sleep_demo。本例在 Windows MinGW 和 Linux GCC 上分别验证;这不等同于复现原项目的 MSVC 诊断。
这里的断言只检查标准相对等待没有提前结束,没有设定“必须精确在 20 毫秒返回”的上限。操作系统计时粒度、调度和其他工作会推迟线程重新执行;Sleep(0) 主要用于让出剩余时间片,也不表示等待 0 毫秒后立即独占 CPU。不要用上述接口实现严格实时的脉冲或采样时序。C++ 线程等待要求
等待不等于同步
跳转到“等待不等于同步”两个线程之间需要等待数据时,用互斥量、条件变量或合适的同步对象表达条件。反复“睡一会再看”不能自动建立数据访问的同步关系。
在 GUI 主线程调用这些函数会阻塞事件处理,窗口可能不能重绘或响应输入。Qt 中需要稍后执行界面逻辑时可使用定时器和事件循环;真正耗时的任务需要设计后台执行和结果交付。原 C3861 问题应通过正确声明解决,不能据此把阻塞等待当作所有延迟工作的通用方案。