ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน
ประสานงานเธรดด้วย std::condition_variable และรูปแบบกลุ่มผู้ปฏิบัติงานแบบคลาสสิก
ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน
ตัวแปรเงื่อนไขคืออะไร
ตัวแปรเงื่อนไข ทำให้เธรดรอจนกว่าเธรดอีกตัวจะแจ้งว่าสภาวะหนึ่งเปลี่ยนแปลง ใช้สำหรับประสานงานระหว่างผู้ผลิตและผู้บริโภค
พื้นฐานของ std::condition_variable
ตัวแปรเงื่อนไขทำงานร่วมกับ std::mutex และเงื่อนไขกำกับ เธรดที่รอจะปล่อย lock ขณะรอ และเรียก lock กลับคืนเมื่อถูกปลุก
#include <condition_variable>
#include <mutex>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> tasks;
bool done = false;การรอเงื่อนไข
ใช้ cv.wait(lock, predicate) ซึ่งจะปล่อย lock ของมิวเท็กซ์และให้เธรดหยุดพักจนกว่าจะได้รับการแจ้งเตือนแบบอะตอมิก เมื่อตื่นขึ้น เธรดจะเรียก lock กลับคืนและตรวจสอบเงื่อนไขกำกับ หากเป็นเท็จ ก็จะหยุดพักอีกครั้ง
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !tasks.empty() || done; });การแจ้งเตือน
เธรดผู้ผลิตจะเรียก cv.notify_one() หรือ cv.notify_all() หลังจากเปลี่ยนสถานะ โดยควรถือครองล็อกไว้ระหว่างการเปลี่ยนสถานะ
{
std::lock_guard<std::mutex> lock(mtx);
tasks.push(42);
}
cv.notify_one();รูปแบบผู้ผลิต- consumer
ตัวอย่างคลาสสิก: ผู้ผลิตเพิ่มงานลงในคิว ส่วน consumer รอรับงาน
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !tasks.empty() || done; });
if (done && tasks.empty()) break;
int task = tasks.front();
tasks.pop();
lock.unlock();
process(task);
}
}การตื่นขึ้นโดยไม่มีสัญญาณ
เธรดที่รอตัวแปรเงื่อนไขอาจตื่นขึ้นโดยไม่มีการแจ้งเตือน นั่นคือเหตุผลที่ wait รับเพรดิเคต เพราะจะตรวจสอบซ้ำทุกครั้งที่ตื่นขึ้น
notify_one เทียบกับ notify_all
ใช้ notify_one เมื่อมีผู้รอเพียงหนึ่งรายที่สามารถทำงานต่อได้ ใช้ notify_all เมื่อการเปลี่ยนสถานะส่งผลต่อผู้รอทั้งหมด เช่น สัญญาณปิดระบบ
การรอแบบกำหนดเวลา
wait_for(lock, duration) และ wait_until(lock, time_point) จะตื่นขึ้นเมื่อได้รับการแจ้งเตือนหรือเมื่อหมดเวลา
if (cv.wait_for(lock, 1s, [] { return ready; })) {
/* condition met */
} else {
/* timed out */
}โครงร่างกลุ่มเธรดทำงาน
รูปแบบที่ใช้กันทั่วไปคือให้เธรดทำงานจำนวนคงที่ดึงงานจากคิวที่ใช้ร่วมกัน สร้างโดยใช้มิวเทกซ์ + ตัวแปรเงื่อนไข + คิว + แฟล็กหยุดแบบอะตอมิก
การป้องกันการพลาดการตื่น
แก้ไขสถานะที่ใช้ร่วมกันและเรียก notify_* โดยถือครองมิวเทกซ์ไว้ระหว่างการเปลี่ยนสถานะเสมอ การปล่อยมิวเทกซ์ก่อนการแจ้งเตือนเล็กน้อยก็ทำได้ แต่ต้องตรวจสอบให้ลำดับการดำเนินการถูกต้อง มิฉะนั้นผู้รออาจพลาดการแจ้งเตือนได้
std::counting_semaphore (C++20)
สำหรับการส่งสัญญาณอย่างง่ายที่อาศัยการนับ C++20 ได้เพิ่ม std::counting_semaphore ซึ่งในบางรูปแบบใช้งานง่ายกว่าตัวแปรเงื่อนไข
ระวังภาวะติดตาย
การถือครองล็อกหลายตัวขณะรอตัวแปรเงื่อนไขอาจทำให้เกิดภาวะติดตายได้ ควรล็อกตามลำดับที่สอดคล้องกัน และใช้ std::scoped_lock สำหรับมิวเทกซ์หลายตัว
ตรวจสอบความเข้าใจ
เหตุใด cv.wait(lock, predicate) จึงรับเพรดิเคต แม้ว่าคุณเพียงต้องการรอการแจ้งเตือน
สรุป
ตัวแปรเงื่อนไขใช้ประสานงานเธรดที่กำลังรอการเปลี่ยนสถานะ ใช้ wait(lock, predicate) เพื่อจัดการการตื่นขึ้นโดยไม่มีสัญญาณ แก้ไขสถานะภายใต้มิวเทกซ์ แล้วเรียก notify_one หรือ notify_all หลังจากนั้น
เรียนรู้ C++ ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 51
- บทเรียน
- 203
คำถามที่พบบ่อย
บทเรียน “ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน”
ประสานงานเธรดด้วย std::condition_variable และรูปแบบกลุ่มผู้ปฏิบัติงานแบบคลาสสิก คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม
ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- std::thread: การรวมและการแยกเธรด
- std::mutex, lock_guard และ unique_lock
- ตัวแปรเงื่อนไขและรูปแบบผู้ปฏิบัติงาน
- พื้นฐาน std::async และ std::future