Время — деньги: как усыпить поток в C++ на миллисекунды

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Когда каждая миллисекунда на счету: зачем нужен точный сон в C++

Представьте, что вы пишете игру, где враги атакуют каждые 500 мс. Или разрабатываете промышленный контроллер, который опрашивает датчик строго раз в 10 мс. Или просто хотите сделать анимацию загрузки с плавным появлением текста. Во всех этих случаях вам понадобится команда: sleep for milliseconds.

Казалось бы, что сложного — «усыпить» поток на заданное время? Но в C++, в отличие от Python или JavaScript, нет единой встроенной функции «подожди N миллисекунд». Точнее, она есть, но в разных операционных системах и стандартах — своя. А ещё есть подводные камни: точность, переносимость, влияние на производительность.

В этой статье мы разберём все способы сделать задержку в C++ на миллисекунды: от старых добрых Sleep() и usleep() до современного std::this_thread::sleep_for(). Вы получите готовые примеры кода, узнаете, какой метод выбрать под свою задачу, и научитесь избегать типичных ошибок.

Стандартный способ: std::this_thread::sleep_for (C++11 и новее)

Начиная со стандарта C++11, в языке появилась библиотека <chrono> и возможность переносимой задержки потока. Это самый правильный и рекомендуемый метод для современного C++ кода.

Как это работает

Функция std::this_thread::sleep_for() принимает временной интервал, заданный с помощью std::chrono::duration. Вы просто указываете количество миллисекунд, и поток «засыпает» на это время.

Пример 1: Базовая задержка на 500 мс

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

int main() {
    std::cout << "Начинаем отсчёт...\n";
    
    // Задержка на 500 миллисекунд
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    
    std::cout << "Прошло полсекунды!\n";
    return 0;
}

Этот код будет работать на Windows, Linux, macOS и любой другой платформе с компилятором C++11/14/17/20. Никаких #ifdef, никаких системных вызовов.

Пример 2: Задержка с переменной

Если вам нужно задавать время динамически:

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

void process_with_delay(int delay_ms) {
    std::cout << "Обработка с задержкой " << delay_ms << " мс...\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
    std::cout << "Готово!\n";
}

int main() {
    process_with_delay(200);
    process_with_delay(1000);
    return 0;
}

Важно: точность sleep_for

Функция sleep_for() не гарантирует абсолютную точность до микросекунд. Реальное время пробуждения может быть немного больше (на несколько миллисекунд) из-за планировщика операционной системы. Для большинства задач (анимации, таймауты, опрос датчиков) этого достаточно. Если же вам нужна микросекундная точность — смотрите раздел «Когда точность критична».

Классический способ: Sleep() для Windows

Если вы пишете код только под Windows (например, старый проект на Visual Studio), можно использовать функцию Sleep() из API Windows. Она «спит» именно в миллисекундах.

Пример 3: Задержка на 1 секунду под Windows

#include <iostream>
#include <windows.h> // Обязательно подключить

int main() {
    std::cout << "Ждём 1 секунду (Windows)...\n";
    Sleep(1000); // Аргумент в миллисекундах
    std::cout << "Проснулись!\n";
    return 0;
}

Минусы:

  • Не работает на Linux/macOS.
  • Требует подключения <windows.h>, что может вызвать конфликты имён.
  • Не использует современные возможности C++.

Когда использовать: только если вы поддерживаете легаси-код или пишете что-то строго под Windows (например, драйвер или DirectX-приложение). В остальных случаях — забудьте.

Старый добрый UNIX-способ: usleep() и nanosleep()

В Linux и других UNIX-системах исторически использовались usleep() (задержка в микросекундах) и nanosleep() (наносекунды). Они до сих пор работают, но считаются устаревшими.

Пример 4: usleep (микросекунды, POSIX)

#include <iostream>
#include <unistd.h> // Для usleep

int main() {
    std::cout << "Задержка 500 мс (Linux)...\n";
    usleep(500 * 1000); // 500 мс = 500 000 микросекунд
    std::cout << "Проснулись!\n";
    return 0;
}

Пример 5: nanosleep (наносекунды, более точный)

#include <iostream>
#include <time.h> // Для nanosleep

int main() {
    struct timespec ts;
    ts.tv_sec = 0;          // 0 секунд
    ts.tv_nsec = 500000000; // 500 мс = 500 000 000 нс
    
    std::cout << "Задержка 500 мс (nanosleep)...\n";
    nanosleep(&ts, NULL);
    std::cout << "Проснулись!\n";
    return 0;
}

Недостатки: опять же — отсутствие переносимости. usleep() удалён из POSIX.1-2008, а nanosleep() хоть и жив, но менее удобен, чем sleep_for.

Сравнение всех методов: что выбрать?

Чтобы вам было проще ориентироваться, вот наглядная таблица:

Метод Переносимость Точность Стандарт C++ Рекомендация
std::this_thread::sleep_for ✅ Все платформы Средняя (1-15 мс) C++11+ Всегда
Sleep()

Блоги

Рекомендаций по книгам