ฉันอ่านบนpthread.h; ฟังก์ชันเงื่อนไขที่เกี่ยวข้องกับตัวแปร (เช่นpthread_cond_wait(3)) ต้องการ mutex เป็นอาร์กิวเมนต์ ทำไม? เท่าที่ผมสามารถบอกได้ว่าผมจะได้รับการสร้าง mutex เพียงเพื่อใช้เป็นข้อโต้แย้งที่? Mutex นั้นควรทำอะไร?
ฉันอ่านบนpthread.h; ฟังก์ชันเงื่อนไขที่เกี่ยวข้องกับตัวแปร (เช่นpthread_cond_wait(3)) ต้องการ mutex เป็นอาร์กิวเมนต์ ทำไม? เท่าที่ผมสามารถบอกได้ว่าผมจะได้รับการสร้าง mutex เพียงเพื่อใช้เป็นข้อโต้แย้งที่? Mutex นั้นควรทำอะไร?
คำตอบ:
มันเป็นเพียงวิธีการที่ปรับใช้ตัวแปรเงื่อนไข (หรือเริ่มต้น)
mutex ใช้ในการป้องกันตัวแปรสภาพตัวเอง นั่นเป็นเหตุผลที่คุณต้องล็อคมันก่อนที่จะรอ
การรอจะเป็นการปลดล็อค mutex ทำให้ผู้อื่นสามารถเข้าถึงตัวแปรเงื่อนไขได้ (สำหรับการส่งสัญญาณ) จากนั้นเมื่อตัวแปรเงื่อนไขถูกส่งสัญญาณหรือออกอากาศไปหนึ่งเธรดในรายการที่รอจะถูกปลุกและ mutex จะถูกล็อกอย่างน่าอัศจรรย์อีกครั้งสำหรับเธรดนั้น
โดยทั่วไปคุณจะเห็นการดำเนินการต่อไปนี้พร้อมกับตัวแปรเงื่อนไขซึ่งแสดงวิธีการทำงานของมัน ตัวอย่างต่อไปนี้เป็นเธรดผู้ปฏิบัติงานซึ่งให้งานผ่านสัญญาณไปยังตัวแปรเงื่อนไข
thread:
    initialise.
    lock mutex.
    while thread not told to stop working:
        wait on condvar using mutex.
        if work is available to be done:
            do the work.
    unlock mutex.
    clean up.
    exit thread.
งานเสร็จภายในลูปนี้หากว่ามีบางอย่างพร้อมใช้งานเมื่อการรอส่งคืน เมื่อเธรดถูกตั้งค่าสถานะเพื่อหยุดการทำงาน (โดยปกติเธรดอื่นจะตั้งค่าเงื่อนไขการออกจากนั้นก็เตะตัวแปรเงื่อนไขเพื่อปลุกเธรดนี้ขึ้น) ลูปจะออกจากการทำงาน mutex จะถูกปลดล็อกและเธรดนี้จะออก
รหัสด้านบนเป็นรุ่นสำหรับผู้บริโภครายเดียวเนื่องจาก Mutex ยังคงล็อคอยู่ในขณะที่กำลังทำงาน สำหรับรูปแบบที่หลากหลายผู้บริโภคคุณสามารถใช้เป็นตัวอย่าง :
thread:
    initialise.
    lock mutex.
    while thread not told to stop working:
        wait on condvar using mutex.
        if work is available to be done:
            copy work to thread local storage.
            unlock mutex.
            do the work.
            lock mutex.
    unlock mutex.
    clean up.
    exit thread.
ทำให้ผู้บริโภครายอื่นได้รับงานขณะที่ทำงานอยู่
ตัวแปรเงื่อนไขช่วยลดภาระการโพลให้คุณแทนที่จะอนุญาตให้เธรดอื่นแจ้งให้คุณทราบเมื่อมีบางสิ่งที่จำเป็นต้องเกิดขึ้น เธรดอื่นสามารถบอกได้ว่าเธรดที่ทำงานนั้นมีอยู่ดังนี้:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
ส่วนใหญ่ของสิ่งที่มักจะผิดพลาดที่เรียกว่าการเสแสร้งโดยทั่วไปมักจะเป็นเพราะหลายกระทู้มีสัญญาณในการpthread_cond_waitโทร (ออกอากาศ) พวกเขาจะกลับมาพร้อมกับ mutex ทำงานแล้วรออีกครั้ง
จากนั้นเธรดที่มีสัญญาณที่สองจะออกมาเมื่อไม่มีงานต้องทำ ดังนั้นคุณต้องมีตัวแปรพิเศษที่บ่งบอกว่างานควรจะทำ (นี่คือการป้องกัน mutex โดยเนื้อแท้กับคู่ condvar / mutex ที่นี่ - เธรดอื่น ๆ จำเป็นต้องล็อค mutex ก่อนที่จะเปลี่ยนอย่างไรก็ตาม)
มันเป็นไปได้ในทางเทคนิคสำหรับเธรดที่จะกลับมาจากการรอเงื่อนไขโดยไม่ถูกเตะโดยกระบวนการอื่น (นี่คือการปลุกที่ผิดจริง) แต่ในช่วงเวลาหลายปีที่ฉันทำงานกับ pthreads ทั้งในการพัฒนา / บริการของรหัสและในฐานะผู้ใช้ ของพวกเขาฉันไม่เคยได้รับหนึ่งในเหล่านี้ อาจเป็นเพราะ HP มีการใช้งานที่เหมาะสม :-)
ไม่ว่าในกรณีใดรหัสเดียวกันกับที่จัดการกับกรณีที่ผิดพลาดนั้นก็จัดการกับการปลุกแบบปลอมด้วยเช่นกันเนื่องจากจะไม่มีการตั้งค่าสถานะการทำงานที่พร้อมใช้งานให้
do somethingภายในwhileวง
                    ตัวแปรเงื่อนไขค่อนข้าง จำกัด หากคุณสามารถส่งสัญญาณเงื่อนไขได้โดยปกติคุณต้องจัดการข้อมูลบางอย่างที่เกี่ยวข้องกับเงื่อนไขที่ถูกส่งสัญญาณ การส่งสัญญาณ / การปลุกจะต้องทำโดยใช้อะตอมเพื่อให้บรรลุถึงสิ่งนั้นโดยไม่ต้องแนะนำสภาพการแข่งขันหรือซับซ้อนเกินไป
pthreads ยังสามารถให้คุณด้วยเหตุผลทางเทคนิคมากกว่าการปลุกปลอม นั่นหมายความว่าคุณต้องตรวจสอบเพรดิเคตเพื่อให้มั่นใจได้ว่าสภาพสัญญาณจริง - และแยกแยะความแตกต่างจากการตื่นขึ้น การตรวจสอบเงื่อนไขดังกล่าวเกี่ยวกับการรอคอยนั้นจำเป็นต้องได้รับการปกป้องดังนั้นตัวแปรเงื่อนไขจำเป็นต้องมีวิธีการรอ / ปลุกโดยใช้อะตอมมิคในขณะที่ล็อค / ปลดล็อก mutex ที่ป้องกันสภาพนั้น
ลองพิจารณาตัวอย่างง่ายๆที่คุณได้รับแจ้งว่ามีการสร้างข้อมูลบางส่วน อาจมีเธรดอื่นสร้างข้อมูลบางส่วนที่คุณต้องการและตั้งตัวชี้ไปยังข้อมูลนั้น
จินตนาการว่าเธรดผู้ผลิตให้ข้อมูลแก่ผู้บริโภคเธรดอื่นผ่านตัวชี้ 'some_data'
while(1) {
    pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
    char *data = some_data;
    some_data = NULL;
    handle(data);
}
คุณจะได้รับสภาพการแข่งขันมากมายโดยธรรมชาติจะเกิดอะไรขึ้นถ้าอีกเธรดหนึ่งทำงานsome_data = new_dataหลังจากที่คุณตื่นขึ้นมา แต่ก่อนที่คุณจะทำdata = some_data
คุณไม่สามารถสร้าง mutex ของคุณเองเพื่อป้องกันกรณีนี้เช่น
while(1) {
    pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
    pthread_mutex_lock(&mutex);
    char *data = some_data;
    some_data = NULL;
    pthread_mutex_unlock(&mutex);
    handle(data);
}
จะไม่ทำงาน แต่ก็ยังมีโอกาสที่จะมีสภาพการแข่งขันในระหว่างการตื่นขึ้นมาและการคว้า mutex การวาง mutex ก่อน pthread_cond_wait จะไม่ช่วยคุณเนื่องจากคุณจะถือ mutex ระหว่างรอ - นั่นคือผู้ผลิตจะไม่สามารถคว้า mutex ได้ (หมายเหตุในกรณีนี้คุณสามารถสร้างตัวแปรเงื่อนไขที่สองเพื่อส่งสัญญาณผู้ผลิตที่คุณทำด้วยsome_data- แม้ว่าสิ่งนี้จะซับซ้อนโดยเฉพาะถ้าคุณต้องการผู้ผลิต / ผู้บริโภคจำนวนมาก)
ดังนั้นคุณต้องมีวิธีในการปล่อย / จับ mutex แบบอะตอมเมื่อรอ / ตื่นจากสภาพ นั่นคือสิ่งที่ตัวแปรเงื่อนไข pthread ทำและนี่คือสิ่งที่คุณต้องการ:
while(1) {
    pthread_mutex_lock(&mutex);
    while(some_data == NULL) { // predicate to acccount for spurious wakeups,would also 
                               // make it robust if there were several consumers
       pthread_cond_wait(&cond,&mutex); //atomically lock/unlock mutex
    }
    char *data = some_data;
    some_data = NULL;
    pthread_mutex_unlock(&mutex);
    handle(data);
}
(ผู้ผลิตจะต้องใช้ความระมัดระวังเหมือนกันโดยธรรมชาติเสมอปกป้อง 'some_data' ด้วย mutex เดียวกันและทำให้แน่ใจว่าจะไม่เขียนทับ some_data ถ้า some_data อยู่ในขณะนี้! = NULL)
while (some_data != NULL)จะเป็นห่วงในขณะที่ทำเพื่อรอตัวแปรเงื่อนไขอย่างน้อยหนึ่งครั้ง?
                    while(some_data != NULL)จะเป็นwhile(some_data == NULL)?
                    ตัวแปรเงื่อนไข POSIX ไม่มีสถานะ ดังนั้นจึงเป็นความรับผิดชอบของคุณในการรักษาสถานะ เนื่องจากสถานะจะสามารถเข้าถึงได้โดยเธรดทั้งสองที่รอและเธรดที่บอกเธรดอื่นให้หยุดรอดังนั้นจึงต้องมีการป้องกันโดย mutex หากคุณคิดว่าคุณสามารถใช้ตัวแปรเงื่อนไขได้โดยไม่ต้องมี mutex คุณจะไม่เข้าใจว่าตัวแปรเงื่อนไขนั้นไร้สถานะ
ตัวแปรเงื่อนไขถูกสร้างขึ้นรอบ ๆ เงื่อนไข เธรดที่รอตัวแปรเงื่อนไขกำลังรอเงื่อนไขบางอย่าง เธรดที่ตัวแปรเงื่อนไขสัญญาณเปลี่ยนเงื่อนไขนั้น ตัวอย่างเช่นเธรดอาจกำลังรอข้อมูลบางอย่างมาถึง เธรดอื่น ๆ อาจสังเกตเห็นว่าข้อมูลมาถึงแล้ว "ข้อมูลมาถึงแล้ว" เป็นเงื่อนไข
นี่คือการใช้คลาสสิกของตัวแปรเงื่อนไขง่าย:
while(1)
{
    pthread_mutex_lock(&work_mutex);
    while (work_queue_empty())       // wait for work
       pthread_cond_wait(&work_cv, &work_mutex);
    work = get_work_from_queue();    // get work
    pthread_mutex_unlock(&work_mutex);
    do_work(work);                   // do that work
}
ดูว่าเธรดกำลังรองานอยู่อย่างไร งานได้รับการคุ้มครองโดย mutex การรอจะปล่อย mutex เพื่อให้เธรดอื่นสามารถให้เธรดนี้ทำงานได้ นี่คือวิธีที่จะให้สัญญาณ:
void AssignWork(WorkItem work)
{
    pthread_mutex_lock(&work_mutex);
    add_work_to_queue(work);           // put work item on queue
    pthread_cond_signal(&work_cv);     // wake worker thread
    pthread_mutex_unlock(&work_mutex);
}
ขอให้สังเกตว่าคุณต้องการ mutex เพื่อป้องกันคิวงาน ขอให้สังเกตว่าตัวแปรเงื่อนไขตัวเองไม่รู้ว่าทำงานหรือไม่ นั่นคือตัวแปรเงื่อนไขจะต้องเชื่อมโยงกับเงื่อนไขเงื่อนไขนั้นจะต้องได้รับการบำรุงรักษาโดยรหัสของคุณและเนื่องจากมีการแชร์ในหมู่เธรดจึงต้องได้รับการปกป้องโดย mutex
ฟังก์ชันตัวแปรเงื่อนไขบางฟังก์ชันไม่จำเป็นต้องมี mutex: มีเพียงการดำเนินการที่รอคอยเท่านั้น การดำเนินการของสัญญาณและการออกอากาศไม่จำเป็นต้องมี mutex ตัวแปรเงื่อนไขยังไม่ได้เชื่อมโยงกับ mutex เฉพาะอย่างถาวร Mutex ภายนอกไม่ได้ป้องกันตัวแปรเงื่อนไข หากตัวแปรเงื่อนไขมีสถานะภายในเช่นคิวของเธรดที่รออยู่สิ่งนี้จะต้องได้รับการปกป้องโดยการล็อกภายในภายในตัวแปรเงื่อนไข
การดำเนินการรอรวบรวมตัวแปรเงื่อนไขและ mutex ไว้ด้วยกันเนื่องจาก:
ด้วยเหตุผลนี้การดำเนินการรอใช้เป็นอาร์กิวเมนต์ทั้ง mutex และเงื่อนไข: เพื่อให้สามารถจัดการการถ่ายโอนอะตอมของเธรดจากการเป็นเจ้าของ mutex เพื่อรอเพื่อให้เธรดไม่ตกเป็นเหยื่อของสภาพการแข่งขันตื่นขึ้นมาที่หายไปการปลุกหายไปถึงสภาพการแข่งขัน
สภาพการแข่งขัน Wakeup ที่หายไปจะเกิดขึ้นหากเธรดเลิกใช้ mutex แล้วรอวัตถุการซิงโครไนซ์แบบไร้สถานะ แต่ในทางที่ไม่ใช่อะตอม: มีหน้าต่างเวลาเมื่อเธรดไม่มีการล็อกอีกต่อไปและมี ยังไม่ได้เริ่มรอวัตถุ ในระหว่างหน้าต่างนี้เธรดอื่นสามารถเข้ามาทำให้เงื่อนไขที่รอเป็นจริงส่งสัญญาณการซิงโครไนซ์ไร้รัฐแล้วหายไป วัตถุไร้สัญชาติจำไม่ได้ว่าเป็นสัญญาณ (ไร้สัญชาติ) ดังนั้นเธรดดั้งเดิมจะเข้าสู่โหมดสลีปออบเจ็กต์แบบไร้รัฐและไม่ตื่นขึ้นแม้ว่าเงื่อนไขที่ต้องการจะเป็นจริงแล้ว: การปลุกที่หายไป
ฟังก์ชันการรอตัวแปรเงื่อนไขหลีกเลี่ยงการปลุกที่หายไปโดยตรวจสอบให้แน่ใจว่าเธรดการโทรถูกลงทะเบียนเพื่อจับการปลุกก่อนที่จะเลิก mutex สิ่งนี้จะเป็นไปไม่ได้ถ้าฟังก์ชัน condition variable wait ไม่ได้ใช้ mutex เป็นอาร์กิวเมนต์
pthread_cond_broadcastและpthread_cond_signalการดำเนินการ (ที่คำถาม SO นี้เกี่ยวกับ) ไม่ได้ใช้ mutex เป็นอาร์กิวเมนต์ เพียงเงื่อนไข ข้อมูลจำเพาะ POSIX เป็นที่นี่ Mutex ถูกกล่าวถึงโดยเฉพาะในสิ่งที่เกิดขึ้นในเธรดที่รอเมื่อพวกเขาตื่นขึ้นมา
                    ฉันไม่พบคำตอบอื่นให้กระชับและอ่านง่ายเหมือนหน้านี้ โดยปกติโค้ดที่รอจะมีหน้าตาดังนี้:
mutex.lock()
while(!check())
    condition.wait()
mutex.unlock()
มีสามเหตุผลในการตัดคำwait()ใน mutex:
signal()ก่อนwait()และเราจะพลาดการปลุกนี้check()จะขึ้นอยู่กับการดัดแปลงจากเธรดอื่นดังนั้นคุณต้องแยกออกจากกันประเด็นที่สามไม่ได้เป็นปัญหาเสมอไป - บริบททางประวัติศาสตร์เชื่อมโยงจากบทความถึง การสนทนานี้
การแจ้งเตือนแบบปลอมมักถูกกล่าวถึงเกี่ยวกับกลไกนี้ (เช่นเธรดที่รออยู่นั้นถูกปลุกโดยไม่signal()ถูกเรียก) check()อย่างไรก็ตามเหตุการณ์ดังกล่าวจะถูกจัดการโดยคล้อง
ตัวแปรเงื่อนไขเกี่ยวข้องกับ mutex เพราะเป็นวิธีเดียวที่สามารถหลีกเลี่ยงการแข่งขันที่ถูกออกแบบมาเพื่อหลีกเลี่ยง
// incorrect usage:
// thread 1:
while (notDone) {
    pthread_mutex_lock(&mutex);
    bool ready = protectedReadyToRunVariable
    pthread_mutex_unlock(&mutex);
    if (ready) {
        doWork();
    } else {
        pthread_cond_wait(&cond1); // invalid syntax: this SHOULD have a mutex
    }
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
   protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
Now, lets look at a particularly nasty interleaving of these operations
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable;
pthread_mutex_unlock(&mutex);
                                 pthread_mutex_lock(&mutex);
                                 protectedReadyToRuNVariable = true;
                                 pthread_mutex_unlock(&mutex);
                                 pthread_cond_signal(&cond1);
if (ready) {
pthread_cond_wait(&cond1); // uh o!
ณ จุดนี้ไม่มีเธรดที่จะส่งสัญญาณตัวแปรเงื่อนไขดังนั้น thread1 จะรอตลอดไปแม้ว่าการป้องกัน READToRunVariable ที่มีการป้องกันจะกล่าวว่าพร้อมที่จะไป!
วิธีการเดียวสำหรับสิ่งนี้คือตัวแปรเงื่อนไขเพื่อปล่อย mutex แบบอะตอมในขณะที่เริ่มต้นพร้อมที่จะรอตัวแปรเงื่อนไข นี่คือสาเหตุที่ฟังก์ชัน cond_wait ต้องการ mutex
// correct usage:
// thread 1:
while (notDone) {
    pthread_mutex_lock(&mutex);
    bool ready = protectedReadyToRunVariable
    if (ready) {
        pthread_mutex_unlock(&mutex);
        doWork();
    } else {
        pthread_cond_wait(&mutex, &cond1);
    }
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
   protectedReadyToRuNVariable = true;
   pthread_cond_signal(&mutex, &cond1);
pthread_mutex_unlock(&mutex);
              mutex ควรถูกล็อคเมื่อคุณโทร pthread_cond_wait ; เมื่อคุณเรียกมันว่าทั้งสองจะปลดล็อค mutex และบล็อกเงื่อนไข เมื่อเงื่อนไขถูกส่งสัญญาณมันจะล็อคอะตอมอีกครั้งและส่งกลับ
สิ่งนี้อนุญาตให้ใช้งานการจัดตารางเวลาที่สามารถคาดการณ์ได้หากต้องการในเธรดที่จะทำการส่งสัญญาณสามารถรอจนกว่า mutex จะถูกปล่อยเพื่อทำการประมวลผลแล้วส่งสัญญาณเงื่อนไข
ฉันทำแบบฝึกหัดในชั้นเรียนถ้าคุณต้องการตัวอย่างจริงของตัวแปรเงื่อนไข:
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "unistd.h"
int compteur = 0;
pthread_cond_t varCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_compteur;
void attenteSeuil(arg)
{
    pthread_mutex_lock(&mutex_compteur);
        while(compteur < 10)
        {
            printf("Compteur : %d<10 so i am waiting...\n", compteur);
            pthread_cond_wait(&varCond, &mutex_compteur);
        }
        printf("I waited nicely and now the compteur = %d\n", compteur);
    pthread_mutex_unlock(&mutex_compteur);
    pthread_exit(NULL);
}
void incrementCompteur(arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex_compteur);
            if(compteur == 10)
            {
                printf("Compteur = 10\n");
                pthread_cond_signal(&varCond);
                pthread_mutex_unlock(&mutex_compteur);
                pthread_exit(NULL);
            }
            else
            {
                printf("Compteur ++\n");
                compteur++;
            }
        pthread_mutex_unlock(&mutex_compteur);
    }
}
int main(int argc, char const *argv[])
{
    int i;
    pthread_t threads[2];
    pthread_mutex_init(&mutex_compteur, NULL);
    pthread_create(&threads[0], NULL, incrementCompteur, NULL);
    pthread_create(&threads[1], NULL, attenteSeuil, NULL);
    pthread_exit(NULL);
}
              มันเป็นการตัดสินใจออกแบบที่เฉพาะเจาะจงมากกว่าความต้องการทางความคิด
สำหรับเอกสาร pthreads เหตุผลที่ไม่ได้แยก mutex นั้นคือมีการปรับปรุงประสิทธิภาพที่สำคัญโดยรวมพวกเขาและพวกเขาคาดหวังว่าเนื่องจากเงื่อนไขการแข่งขันทั่วไปหากคุณไม่ได้ใช้ mutex มันเกือบจะทำอยู่แล้ว
https://linux.die.net/man/3/pthread_cond_wait
คุณสมบัติของ Mutexes และตัวแปรเงื่อนไข
มีข้อเสนอแนะว่าการได้มาและการเปิดเผย mutex จะถูกแยกออกจากการรอเงื่อนไข สิ่งนี้ถูกปฏิเสธเนื่องจากเป็นลักษณะที่รวมกันของการดำเนินการซึ่งในความเป็นจริงแล้วจะช่วยให้เกิดการใช้งานแบบเรียลไทม์ การประยุกต์ใช้เหล่านั้นสามารถย้ายเธรดที่มีลำดับความสำคัญสูงระหว่างตัวแปรเงื่อนไขและ mutex ในลักษณะที่โปร่งใสให้กับผู้เรียก สิ่งนี้สามารถป้องกันการสลับบริบทเพิ่มเติมและจัดเตรียมการได้มาซึ่ง mutex ที่กำหนดได้มากขึ้นเมื่อเธรดที่รออยู่ถูกส่งสัญญาณ ดังนั้นปัญหาความเป็นธรรมและลำดับความสำคัญสามารถจัดการได้โดยตรงโดยการกำหนดเวลา นอกจากนี้การดำเนินการรอสภาพปัจจุบันตรงกับแนวปฏิบัติที่มีอยู่
มีผู้ exegeses มากมายเกี่ยวกับเรื่องนั้น แต่ฉันต้องการที่จะเป็นตัวอย่างที่ชัดเจนด้วยตัวอย่างต่อไปนี้
1 void thr_child() {
2    done = 1;
3    pthread_cond_signal(&c);
4 }
5 void thr_parent() {
6    if (done == 0)
7        pthread_cond_wait(&c);
8 }
เกิดอะไรขึ้นกับข้อมูลโค้ด แค่ไตร่ตรองบ้างก่อนจะไปข้างหน้า
ปัญหาเป็นเรื่องที่ลึกซึ้งอย่างแท้จริง หากผู้ปกครองเรียกใช้
 thr_parent()แล้ว vets มูลค่าของdoneมันจะเห็นว่ามันเป็น0และพยายามที่จะไปนอน แต่ก่อนที่จะมีสายรอให้เข้านอนพ่อแม่จะถูกขัดจังหวะระหว่างบรรทัด 6-7 และลูกวิ่ง เด็กเปลี่ยนตัวแปรสถานะ
 doneเป็น1และสัญญาณ แต่ไม่มีเธรดรออยู่และไม่มีเธรดถูกปลุก เมื่อผู้ปกครองทำงานอีกครั้งมันจะนอนหลับตลอดไปซึ่งไม่น่าเชื่อจริงๆ
เกิดอะไรขึ้นถ้าพวกเขาจะดำเนินการในขณะที่ได้รับล็อคเป็นรายบุคคล?