C++
multithreading
concurrency
thread management
C++11

stdthis_threadyield vs stdthis_threadsleep_for

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

std::this_thread::yield() and std::this_thread::sleep_for() both pause the current thread in some sense, but they mean very different things. One is a scheduler hint that says "let someone else run if useful." The other asks the system not to run this thread for at least a specified duration.

What yield() Means

yield() does not sleep for a measurable amount of time. It tells the scheduler that the current thread is willing to give up the rest of its current time slice. The operating system may then run another ready thread, or it may schedule the same thread again immediately.

That makes yield() useful only in narrow situations, such as a very short spin wait:

cpp
1#include <atomic>
2#include <iostream>
3#include <thread>
4
5int main() {
6    std::atomic<bool> ready{false};
7
8    std::thread worker([&ready] {
9        while (!ready.load()) {
10            std::this_thread::yield();
11        }
12        std::cout << "worker proceeds\n";
13    });
14
15    std::this_thread::sleep_for(std::chrono::milliseconds(100));
16    ready.store(true);
17    worker.join();
18}

Even here, yield() is a compromise, not an ideal waiting mechanism.

What sleep_for() Means

sleep_for() requests that the thread be suspended for at least the given duration:

cpp
1#include <chrono>
2#include <iostream>
3#include <thread>
4
5int main() {
6    std::cout << "waiting...\n";
7    std::this_thread::sleep_for(std::chrono::milliseconds(250));
8    std::cout << "done\n";
9}

This is appropriate when you deliberately want a delay, backoff, or periodic loop. It reduces CPU usage because the thread is not busy checking a condition the whole time.

However, the wake-up time is not exact. The thread sleeps for at least that long, and often a little longer depending on timer granularity and scheduler load.

They Solve Different Problems

Use yield() when:

  • you are in a very short-lived retry loop
  • another thread may make progress immediately
  • sleeping for a fixed duration would add unnecessary latency

Use sleep_for() when:

  • you want a real delay
  • you are polling with a known interval
  • you want to back off after a failed attempt

For example, retry logic is a natural fit for sleep_for():

cpp
1for (int attempt = 0; attempt < 5; ++attempt) {
2    if (try_connect()) {
3        break;
4    }
5    std::this_thread::sleep_for(std::chrono::milliseconds(200));
6}

Using yield() in that kind of loop would burn CPU while providing no useful timing control.

The Better Answer Is Often Neither

In many cases, both functions are the wrong abstraction. If a thread is waiting for a condition, a synchronization primitive is usually better:

cpp
1#include <condition_variable>
2#include <iostream>
3#include <mutex>
4#include <thread>
5
6int main() {
7    std::mutex m;
8    std::condition_variable cv;
9    bool ready = false;
10
11    std::thread worker([&] {
12        std::unique_lock<std::mutex> lock(m);
13        cv.wait(lock, [&] { return ready; });
14        std::cout << "worker proceeds\n";
15    });
16
17    {
18        std::lock_guard<std::mutex> lock(m);
19        ready = true;
20    }
21    cv.notify_one();
22    worker.join();
23}

This avoids both busy-waiting and arbitrary sleep delays.

Performance and Portability Considerations

yield() is highly scheduler-dependent. On one system it may help another ready thread run. On another, it may effectively do almost nothing. That makes it unreliable as a tuning trick unless profiling proves it helps.

sleep_for() is more predictable conceptually, but still not precise enough for strict timing guarantees. It is appropriate for general delays, not for high-precision scheduling.

Common Pitfalls

The biggest pitfall is using yield() as a general waiting strategy. If the wait is longer than a brief handoff, it wastes CPU and can still starve progress.

Another mistake is using sleep_for() to coordinate threads that should really use a mutex, condition variable, semaphore, or atomic protocol. Sleeping does not create correctness; it only delays execution and hopes timing lines up.

Developers also sometimes assume sleep_for(1ms) means "wake exactly one millisecond later." It does not. Real wake-up time depends on the platform scheduler.

Summary

  • 'yield() is a scheduler hint, not a timed delay.'
  • 'sleep_for() suspends the thread for at least a specified duration.'
  • Use yield() only for narrow short spin-wait scenarios.
  • Use sleep_for() for intentional delays, polling, or backoff.
  • If you are waiting for a condition, a synchronization primitive is often better than either.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.