文章目錄
- 多線程開發:wait、sleep、yield全解析
- 1 What
- 簡要介紹
- 詳細介紹
- `wait()` — 條件等待(用于線程同步)
- `sleep()` — 睡覺,定時掛起
- `yield()` — 自愿讓出 CPU
- 2 區別以及建議
- 區別
- 應用場景建議
- 3 三者協作使用示例
多線程開發:wait、sleep、yield全解析
多線程開發中, wait()
、sleep()
和 yield()
的正確使用對于控制線程行為、避免死鎖、提升性能至關重要。
1 What
簡要介紹
方法 | 屬于哪類 | 是否釋放鎖 | 作用 |
---|---|---|---|
wait() | 同步原語(條件變量) | ? 釋放鎖 | 當前線程等待某個條件滿足,掛起執行。 |
sleep() | 時間控制 | ? 不釋放鎖 | 當前線程強制睡眠一段時間。 |
yield() | 調度建議 | ? 不釋放鎖 | 當前線程主動讓出 CPU,允許其他線程執行。 |
詳細介紹
wait()
— 條件等待(用于線程同步)
std::condition_variable::wait()
(C++11)- Java 的
Object.wait()
也類似
行為:
- 線程在等待某個條件成立。
- 釋放所持的互斥鎖(mutex),進入阻塞狀態。
- 條件滿足后,被
notify_one()
/notify_all()
喚醒,重新競爭鎖并繼續執行。
C++ 示例:
std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; }); // 釋放鎖等待條件成立std::cout << "Condition met, working..." << std::endl;
}
sleep()
— 睡覺,定時掛起
std::this_thread::sleep_for()
std::this_thread::sleep_until()
行為:
- 當前線程被強制阻塞指定時間。
- 不會釋放任何鎖。
- 時間一到,線程進入就緒狀態(可被調度)。
示例:
std::mutex mtx;void worker() {std::lock_guard<std::mutex> lock(mtx);std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Wake up after 2 seconds.\n";
}
🔺 注意:如果你在持鎖狀態下調用 sleep()
,會讓其它線程“餓死”或引發死鎖。
yield()
— 自愿讓出 CPU
std::this_thread::yield()
(C++11)- 實際為對操作系統
sched_yield()
的封裝
行為:
- 當前線程主動放棄 CPU 時間片。
- 線程回到就緒隊列,允許其他同優先級線程執行。
- 不會阻塞、不休眠、不釋放鎖。
示例:
void busy_wait() {while (!ready) {std::this_thread::yield(); // 避免 CPU 忙等}
}
2 區別以及建議
區別
特性 | wait() | sleep() | yield() |
---|---|---|---|
阻塞線程? | ? 是 | ? 是 | ? 否(可能暫停) |
是否釋放鎖? | ? 是(必須配合 mutex 使用) | ? 否 | ? 否 |
喚醒條件 | notify_one() / notify_all() | 時間到 | 被 OS 再次調度 |
典型用途 | 線程間同步,條件等待 | 限制頻率、延時模擬 | 忙等時避免 CPU 占用 |
所屬 API | condition_variable / pthread_cond | std::this_thread::sleep_for() | std::this_thread::yield() |
應用場景建議
場景 | 推薦方法 |
---|---|
等待某個狀態改變 | wait() |
模擬延時 / 限速 / 輪詢間隔 | sleep() |
忙等 / 自旋等待中降低 CPU 占用 | yield() |
3 三者協作使用示例
驗證目標:
- 主線程 sleep 控制節奏
- 子線程 yield 等待任務
- 條件變量 wait 同步工作
代碼目標:
- 主線程每 1 秒產生一個任務。
- 工作線程使用
yield()
自旋檢查是否有任務。 - 一旦任務準備好,工作線程使用
wait()
等待條件變量通知,再執行任務。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <chrono>std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> ready{false};
int task_counter = 0;// 工作線程:等待任務并執行
void worker_thread() {while (true) {// ? 自旋檢查任務是否準備好(減少 wait 的頻率)while (!ready.load()) {std::this_thread::yield(); // 主動讓出 CPU}std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [] { return ready.load(); }); // 等待通知,并釋放鎖// 模擬任務處理std::cout << "[Worker] Executing task #" << task_counter << std::endl;ready = false; // 標記任務完成if (task_counter >= 5) break; // 結束條件}
}// 主線程:周期性產生任務
void task_producer() {for (int i = 1; i <= 5; ++i) {std::this_thread::sleep_for(std::chrono::seconds(1)); // 模擬任務生成延遲{std::lock_guard<std::mutex> lock(mtx);task_counter = i;ready = true;std::cout << "[Main] Task #" << i << " ready\n";}cv.notify_one(); // 通知工作線程}
}int main() {std::thread worker(worker_thread);std::thread producer(task_producer);producer.join();worker.join();std::cout << "All tasks finished.\n";return 0;
}
輸出:
[Main] Task #1 ready
[Worker] Executing task #1
[Main] Task #2 ready
[Worker] Executing task #2
[Main] Task #3 ready
[Worker] Executing task #3
[Main] Task #4 ready
[Worker] Executing task #4
[Main] Task #5 ready
[Worker] Executing task #5
All tasks finished.
代碼行為解析:
-
主線程:
- 每秒產生一個任務,調用
sleep_for()
。 - 使用鎖保護
task_counter
和ready
狀態。 - 調用
cv.notify_one()
喚醒工作線程。
- 每秒產生一個任務,調用
-
工作線程:
- 使用
yield()
忙等(在任務未準備好前避免 CPU 占用)。 - 使用
condition_variable::wait()
掛起,等待任務準備。 - 被通知后執行任務,打印日志,重置狀態。
- 使用