首页 > 后端开发 > C++ > 正文

如何在C++中休眠或暂停几秒钟_C++程序延时与休眠实现

穿越時空
发布: 2025-09-24 13:04:01
原创
946人浏览过
C++中实现延时的核心方法包括:1. 使用std::this_thread::sleep_for(推荐跨平台方案),结合chrono库指定时间;2. Windows平台调用Sleep函数(单位毫秒);3. 类Unix系统使用sleep或usleep(后者可能已废弃)。实际休眠时间常因操作系统调度、时钟分辨率和上下文切换开销而长于设定值,导致“不准时”。非阻塞延时可通过时间戳轮询、条件变量超时等待(wait_for)或异步事件驱动模型(如Boost.Asio定时器)实现。多线程中需避免持有锁时休眠,否则会引发死锁或性能问题。

如何在c++中休眠或暂停几秒钟_c++程序延时与休眠实现

C++程序要实现延时或休眠,核心思路是让当前线程暂停执行一段指定的时间。这通常依赖于操作系统提供的API,比如在Windows平台上我们有Sleep函数,而对于跨平台的需求,C++11及更高版本提供了std::this_thread::sleep_for,此外,在类Unix系统上,还有sleepusleep等函数可用。这些方法本质上都是在告诉操作系统:“嘿,我这个线程暂时没什么事要干,让它休息一会儿吧。”

解决方案

在C++中实现程序延时或休眠,我们主要有以下几种常用且可靠的方法:

1. 使用C++标准库(C++11及更高版本):std::this_thread::sleep_for

这是最推荐的跨平台解决方案,它位于<thread>头文件中,并结合<chrono>库来指定延时时长。

立即学习C++免费学习笔记(深入)”;

#include <iostream>
#include <thread> // for std::this_thread::sleep_for
#include <chrono> // for std::chrono::seconds, milliseconds, etc.

int main() {
    std::cout << "程序开始运行..." << std::endl;

    // 休眠2秒
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "休眠2秒后继续执行。" << std::endl;

    // 休眠500毫秒
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::cout << "休眠500毫秒后继续执行。" << std::endl;

    // 休眠100微秒(注意:实际精度受操作系统调度影响)
    std::this_thread::sleep_for(std::chrono::microseconds(100));
    std::cout << "休眠100微秒后继续执行。" << std::endl;

    std::cout << "程序结束。" << std::endl;
    return 0;
}
登录后复制

std::this_thread::sleep_for接受一个std::chrono::duration类型的参数,这使得延时时间的表达非常灵活和直观,比如std::chrono::seconds(N)std::chrono::milliseconds(N)等。

2. 针对Windows平台:Sleep函数

如果你只针对Windows系统开发,可以使用<windows.h>中提供的Sleep函数。

#include <iostream>
#include <windows.h> // for Sleep

int main() {
    std::cout << "程序开始运行 (Windows)..." << std::endl;

    // 休眠3000毫秒 (3秒)
    Sleep(3000);
    std::cout << "休眠3秒后继续执行。" << std::endl;

    std::cout << "程序结束 (Windows)。" << std::endl;
    return 0;
}
登录后复制

需要注意的是,Sleep函数的参数是毫秒数(DWORD类型)。它的缺点是不可移植,只能在Windows上使用。

3. 针对类Unix/POSIX系统(Linux, macOS等):sleepusleep函数

在类Unix系统上,<unistd.h>头文件提供了sleepusleep函数。

  • sleep(unsigned int seconds):参数是秒数。
  • usleep(useconds_t microseconds):参数是微秒数。需要注意的是,usleep在某些系统上可能已被标记为废弃,推荐使用nanosleepstd::this_thread::sleep_for
#include <iostream>
#include <unistd.h> // for sleep and usleep (on POSIX systems)

int main() {
    std::cout << "程序开始运行 (POSIX)..." << std::endl;

    // 休眠1秒
    sleep(1);
    std::cout << "休眠1秒后继续执行。" << std::endl;

    // 休眠500000微秒 (0.5秒)
    // 注意:usleep可能已废弃,但仍可在许多系统上使用
    usleep(500000);
    std::cout << "休眠0.5秒后继续执行。" << std::endl;

    std::cout << "程序结束 (POSIX)。" << std::endl;
    return 0;
}
登录后复制

为了保持代码的现代性和跨平台性,我个人更倾向于使用std::this_thread::sleep_for。它不仅表达力强,而且避免了平台特定的API带来的兼容性问题。

为什么程序休眠会“不准时”?——探究C++延时精度的奥秘

我们经常会发现,即使代码里写明了休眠100毫秒,实际程序暂停的时间却可能不止100毫秒,甚至有时会更长。这背后涉及到操作系统调度、硬件时钟精度等多个复杂因素,理解这些能帮助我们更好地预期程序的行为。

1. 操作系统调度器的“善意延迟”

当你的线程调用sleep_forSleep时,它其实是向操作系统发出了一个请求:“请在指定时间后把我唤醒。”操作系统接收到这个请求后,会将你的线程标记为“休眠”状态,并从CPU的调度队列中移除。等到指定的休眠时间过去后,操作系统会再次将你的线程标记为“可运行”状态,并将其重新放入调度队列。

问题就出在这里:线程被标记为“可运行”后,并不意味着它会立即获得CPU。操作系统还需要根据其调度策略、当前系统负载、其他线程的优先级等因素,来决定何时将CPU分配给你的线程。如果此时有更高优先级的任务,或者CPU正忙于处理其他大量工作,你的线程可能就需要排队等待,这就导致了实际唤醒时间晚于预期。所以,sleep_for等函数提供的只是一个最小休眠时间,而不是一个精确的唤醒时间点。

2. 系统时钟分辨率的限制

操作系统的内部计时器并不是无限精确的。它有一个固定的“滴答”(tick)间隔,比如在Windows上,默认的系统时钟分辨率通常在10到15毫秒之间。这意味着,即使你请求休眠1毫秒,操作系统也可能只能在下一个10毫秒的“滴答”时才能处理这个请求,导致实际休眠时间被向上取整。

你可以通过一些API(如Windows上的timeBeginPeriod)来提高系统时钟的分辨率,但这通常会增加系统功耗和CPU开销,因为它会强制操作系统更频繁地检查计时器。在非特殊场景下,不建议随意修改系统时钟分辨率。

3. 上下文切换的开销

当一个线程被唤醒并重新获得CPU时,操作系统需要执行一系列的“上下文切换”操作,包括保存前一个线程的状态,加载当前线程的状态(寄存器、内存映射等)。这些操作本身就需要消耗一定的时间,虽然通常是微秒级别,但在对时间精度要求极高的场景下,这也可能成为累积误差的一部分。

代码小浣熊
代码小浣熊

代码小浣熊是基于商汤大语言模型的软件智能研发助手,覆盖软件需求分析、架构设计、代码编写、软件测试等环节

代码小浣熊 396
查看详情 代码小浣熊

为了更直观地感受这种“不准时”,我们可以用std::chrono::high_resolution_clock来测量实际的休眠时间:

#include <iostream>
#include <thread>
#include <chrono>

int main() {
    auto start_time = std::chrono::high_resolution_clock::now();
    std::cout << "尝试休眠100毫秒..." << std::endl;

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    auto end_time = std::chrono::high_resolution_clock::now();
    auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();

    std::cout << "实际休眠时间: " << elapsed_ms << " 毫秒。" << std::endl;
    // 很多时候,你会发现 elapsed_ms 会略大于 100
    return 0;
}
登录后复制

因此,在设计需要精确时间控制的程序时,我们应该避免过度依赖sleep_for的绝对精度,而更多地考虑使用循环检查时间差(非阻塞延时)或专门的实时操作系统(RTOS)。

除了直接休眠,C++还有哪些非阻塞的延时方案?

直接的sleep函数会阻塞当前线程,这意味着在休眠期间,该线程无法执行任何其他任务。但在许多场景下,我们希望程序在等待某个时间点的同时,还能做一些其他事情,或者至少不完全停止响应。这时,非阻塞的延时方案就显得尤为重要了。

1. 基于时间戳的轮询(Polling)

这是最常见也最容易实现的非阻塞延时方法。其核心思想是:不让线程直接休眠,而是让它在一个循环中持续执行其他任务,并定期检查自上次某个事件发生以来经过了多少时间。当时间达到预设的延时时,就执行相应的操作。

这种方法尤其适用于游戏循环、GUI事件处理或需要周期性检查状态的后台任务。

#include <iostream>
#include <chrono>
#include <thread> // 模拟其他工作

int main() {
    auto last_action_time = std::chrono::steady_clock::now();
    const auto interval = std::chrono::seconds(2); // 每2秒执行一次操作

    std::cout << "程序开始运行,将每2秒执行一次操作..." << std::endl;

    for (int i = 0; i < 10; ++i) { // 模拟运行10次
        auto current_time = std::chrono::steady_clock::now();
        if (current_time - last_action_time >= interval) {
            std::cout << "时间到!执行周期性操作 " << i + 1 << "。" << std::endl;
            last_action_time = current_time; // 更新上次操作时间
        }

        // 模拟当前线程在等待期间执行的其他轻量级工作
        // 比如处理用户输入、渲染帧、检查网络状态等
        std::cout << "  执行其他工作..." << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟小段的忙碌
    }

    std::cout << "程序结束。" << std::endl;
    return 0;
}
登录后复制

这种方法的好处是灵活,线程始终处于“活跃”状态,可以随时响应其他事件。缺点是如果“其他工作”太少,它会白白消耗CPU周期进行频繁的时间检查。

2. 使用条件变量(std::condition_variable)的超时等待

std::condition_variable通常用于线程间的同步,但它的wait_forwait_until方法提供了一种带有超时的等待机制。一个线程可以等待某个条件成立,如果条件在指定时间内仍未成立,它就会自动被唤醒。这是一种“半阻塞”状态,因为线程在等待期间是休眠的,但可以被外部事件(notify_one/notify_all)提前唤醒,也可以被超时唤醒。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>

std::mutex mtx;
std::condition_variable cv;
bool data_ready = false;

void consumer_thread() {
    std::unique_lock<std::mutex> lock(mtx);
    std::cout << "消费者线程:等待数据或超时..." << std::endl;

    // 等待数据,最长等待3秒
    if (cv.wait_for(lock, std::chrono::seconds(3), []{ return data_ready; })) {
        std::cout << "消费者线程:收到数据!" << std::endl;
    } else {
        std::cout << "消费者线程:等待超时,数据未就绪。" << std::endl;
    }
}

void producer_thread() {
    std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟生产数据需要1秒
    {
        std::lock_guard<std::mutex> lock(mtx);
        data_ready = true;
        std::cout << "生产者线程:数据已准备好。" << std::endl;
    }
    cv.notify_one(); // 通知消费者数据已就绪
}

int main() {
    std::thread producer(producer_thread);
    std::thread consumer(consumer_thread);

    producer.join();
    consumer.join();

    std::cout << "主线程结束。" << std::endl;
    return 0;
}
登录后复制

在这个例子中,如果生产者在3秒内准备好数据,消费者会被提前唤醒。否则,消费者会在3秒后自动唤醒并报告超时。这比单纯的sleep_for更加智能,因为它允许外部事件提前终止等待。

3. 异步操作和事件驱动模型

更高级的非阻塞延时通常集成在异步编程框架中,例如Boost.Asio库中的deadline_timer。这些框架允许你注册一个回调函数,并指定它在未来某个时间点被执行。底层的I/O服务(io_context)会负责管理这些定时器,并在不阻塞主线程的情况下,在恰当的时机调用你的回调。

这种方式将延时逻辑从主程序流中解耦,使得程序能够同时处理多个异步任务和事件。虽然引入了更高的复杂性,但对于高性能、高并发的网络服务或复杂的用户界面应用来说,这是非常高效且必要的。

例如,Boost.Asio的伪代码概念:

// 概念性代码,非完整可运行
#include <boost/asio.hpp>
#include <iostream>
#include <functional> // for std::bind

void handle_timeout(const boost::system::error_code& error) {
    if (!error) {
        std::cout << "定时器触发!" << std::endl;
    } else {
        std::cerr << "定时器错误: " << error.message() << std::endl;
    }
}

int main() {
    boost::asio::io_context io_context;
    boost::asio::steady_timer timer(io_context, boost::asio::chrono::seconds(3));

    std::cout << "设置一个3秒的定时器..." << std::endl;
    timer.async_wait(handle_timeout); // 异步等待

    // 在等待定时器期间,io_context可以处理其他事件
    std::cout << "主线程正在执行其他任务..." << std::endl;
    io_context.run(); // 运行事件循环,直到所有异步任务完成

    std::cout << "主线程结束。" << std::endl;
    return 0;
}
登录后复制

选择哪种非阻塞延时方案,取决于你的具体需求:是简单的周期性检查,还是复杂的线程同步,亦或是构建高性能的异步系统。

在多线程环境中,休眠函数的使用有哪些“坑”?

在单线程程序中,sleep_for可能只是让程序停顿一下,但在多线程环境下,它的使用就得格外小心了。不当的休眠操作,轻则影响性能,重则可能导致死锁、资源耗尽等严重问题。

1. 持有锁时休眠:死锁与性能瓶颈的温床

这是多线程编程中最常见的陷阱之一。如果一个线程在获得了互斥锁(std::mutex)之后,又调用了sleep_for或其他休眠函数,那么在它休眠的这段时间内,这个锁将一直被它持有。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex common_mutex;
int shared_resource = 0;

void bad_thread_func() {
    std::cout << "线程 " << std::this_thread::get_id() << " 尝试获取锁..." << std::endl;
    std::lock_guard<std::mutex> lock(common_mutex); // 获取锁
    std::cout << "线程 " << std::this_thread::get_id() << " 已获取锁,并开始休眠..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 在持有锁的情况下休眠
    shared_resource++;
    std::cout << "线程 " << std::this_thread::get_id() << " 休眠结束,释放锁。资源值: " << shared_resource << std::endl;
}

void good_thread_func() {
    std::cout << "线程 " << std::this_thread::get_id() << " 准备工作..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 先做一些不依赖锁的工作

    std::cout << "线程 " << std::this_thread::get_id() << " 尝试获取锁..." << std::endl;
    std::lock_guard<std::mutex> lock(common_mutex); // 获取锁
    shared_resource++;
    std::cout << "线程 " << std::this_thread::get_id() << " 已获取锁,修改资源,并释放锁。资源值: " << shared_resource << std::endl;
}

int main() {
    std::thread t1(bad_thread_func);
    std::thread t2(bad_thread_func); // 另一个线程会因为t1持有锁而长时间阻塞

    t1.join();
    t2.join(); // t2会等到t1休眠结束并释放锁后才能继续

    std::cout << "---------------------------------" << std::endl;

    shared_resource = 0; // 重置资源
    std::thread t3(good_thread_func);
    std::thread t4(good_thread_func); // 这两个线程会更高效地竞争锁

    t3.join();
    t4.join();

    return 0;
}
登录后复制

bad_thread_func中的一个线程持有锁并休眠时,其他任何试图获取这个锁的线程都会被无限期地阻塞,直到休眠的线程醒来并释放锁。这不仅

以上就是如何在C++中休眠或暂停几秒钟_C++程序延时与休眠实现的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号