Mengapa fungsi variabel kondisi pthreads memerlukan mutex?

182

Saya sedang membaca pthread.h; variabel terkait kondisi fungsi (seperti pthread_cond_wait(3)) membutuhkan mutex sebagai argumen. Mengapa? Sejauh yang saya tahu, saya akan membuat mutex hanya untuk digunakan sebagai argumen itu? Apa yang seharusnya dilakukan mutex itu?

DAPAT DILAKUKAN
sumber

Jawaban:

194

Hanya saja cara variabel kondisi diterapkan (atau awalnya).

Mutex digunakan untuk melindungi variabel kondisi itu sendiri . Itu sebabnya Anda membutuhkannya terkunci sebelum Anda menunggu.

Penantian akan "secara atomis" membuka mutex, memungkinkan orang lain mengakses variabel kondisi (untuk pensinyalan). Kemudian ketika variabel kondisi diisyaratkan atau disiarkan, satu atau lebih utas pada daftar tunggu akan dibangunkan dan mutex akan dikunci secara ajaib lagi untuk utas itu.

Anda biasanya melihat operasi berikut dengan variabel kondisi, menggambarkan cara kerjanya. Contoh berikut adalah utas pekerja yang diberikan pekerjaan melalui sinyal ke variabel kondisi.

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.

Pekerjaan dilakukan dalam loop ini asalkan ada beberapa yang tersedia ketika menunggu kembali. Ketika utas telah ditandai untuk berhenti melakukan pekerjaan (biasanya oleh utas lain yang mengatur kondisi keluar kemudian menendang variabel kondisi untuk membangunkan utas ini), loop akan keluar, mutex akan terbuka dan utas ini akan keluar.

Kode di atas adalah model konsumen tunggal karena mutex tetap terkunci saat pekerjaan sedang dilakukan. Untuk variasi multi-konsumen, Anda dapat menggunakan, sebagai contoh :

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.

yang memungkinkan konsumen lain untuk menerima pekerjaan saat ini sedang melakukan pekerjaan.

Variabel kondisi membebaskan Anda dari beban polling suatu kondisi alih-alih membiarkan utas lainnya memberi tahu Anda ketika sesuatu perlu terjadi. Utas lain dapat memberi tahu bahwa utas yang berfungsi tersedia sebagai berikut:

lock mutex.
flag work as available.
signal condition variable.
unlock mutex.

Sebagian besar dari apa yang sering keliru disebut wake ups palsu umumnya selalu karena banyak utas telah ditandai dalam pthread_cond_waitpanggilan mereka (siaran), seseorang akan kembali dengan mutex, melakukan pekerjaan, kemudian menunggu kembali.

Kemudian utas sinyal kedua bisa muncul ketika tidak ada pekerjaan yang harus dilakukan. Jadi Anda harus memiliki variabel tambahan yang menunjukkan bahwa pekerjaan harus dilakukan (ini secara inheren dilindungi mutex dengan pasangan condvar / mutex di sini - utas lain yang diperlukan untuk mengunci mutex sebelum mengubahnya namun).

Ini adalah teknis mungkin untuk thread untuk kembali dari kondisi menunggu tanpa ditendang oleh proses lain (ini adalah wakeup palsu asli) tetapi, dalam semua bertahun-tahun saya bekerja di pthreads, baik dalam pengembangan / jasa dari kode dan sebagai pengguna dari mereka, saya tidak pernah sekalipun menerima salah satu dari ini. Mungkin itu hanya karena HP memiliki implementasi yang layak :-)

Dalam kasus apa pun, kode yang sama yang menangani kasus yang salah juga menangani bangun palsu asli juga karena bendera yang tersedia untuk pekerjaan tidak akan ditetapkan untuk mereka.

paxdiablo
sumber
3
'melakukan sesuatu' tidak seharusnya berada di dalam loop while. Anda ingin loop sementara Anda hanya memeriksa kondisi, jika tidak, Anda mungkin juga 'melakukan sesuatu' jika Anda mendapatkan bangun palsu.
no
1
tidak, penanganan kesalahan adalah yang kedua. Dengan pthreads, Anda dapat dibangunkan, tanpa alasan yang jelas (bangun palsu), dan tanpa kesalahan apa pun. Jadi, Anda perlu memeriksa kembali 'beberapa kondisi' setelah Anda bangun.
no
1
Saya tidak yakin saya mengerti. Saya memiliki reaksi yang sama dengan no ; mengapa do somethingdi dalam whileloop?
DAPAT DITERIMA
1
Mungkin saya tidak membuatnya cukup jelas. Loopnya bukan untuk menunggu pekerjaan siap sehingga Anda bisa melakukannya. Loop adalah loop kerja "tak terbatas" utama. Jika Anda kembali dari cond_wait dan flag pekerjaan diatur, Anda melakukan pekerjaan itu kemudian berputar lagi. "while some condition" hanya akan salah ketika Anda ingin utas berhenti melakukan pekerjaan pada titik mana ia akan melepaskan mutex dan kemungkinan besar keluar.
paxdiablo
7
@stefaanv "mutex masih untuk melindungi variabel kondisi, tidak ada cara lain untuk melindunginya": mutex bukan untuk melindungi variabel kondisi; itu untuk melindungi data predikat , tapi saya pikir Anda tahu itu dari membaca komentar Anda yang mengikuti pernyataan itu. Anda dapat memberi sinyal suatu variabel kondisi secara legal, dan didukung penuh oleh implementasi, pasca- unlock dari mutex yang membungkus predikat, dan pada kenyataannya Anda akan meringankan pertengkaran dalam melakukannya dalam beberapa kasus.
WhozCraig
59

Variabel kondisi sangat terbatas jika Anda hanya bisa memberi sinyal kondisi, biasanya Anda perlu menangani beberapa data yang terkait dengan kondisi yang ditandai. Pemberian sinyal / bangun harus dilakukan secara atomis untuk mencapai hal itu tanpa memperkenalkan kondisi balapan, atau menjadi terlalu rumit

pthreads juga dapat memberi Anda, karena alasan teknis, bangun palsu . Itu berarti Anda perlu memeriksa predikat, sehingga Anda bisa memastikan kondisinya benar-benar diberi tanda - dan bedakan itu dari bangun palsu. Memeriksa kondisi seperti itu sehubungan dengan menunggu itu perlu dijaga - jadi variabel kondisi membutuhkan cara untuk menunggu / bangun secara atomik sementara mengunci / membuka kunci mutex yang menjaga kondisi itu.

Pertimbangkan contoh sederhana di mana Anda diberitahu bahwa beberapa data dihasilkan. Mungkin utas lain membuat beberapa data yang Anda inginkan, dan menetapkan pointer ke data itu.

Bayangkan utas produsen memberikan beberapa data ke utas konsumen lain melalui penunjuk '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);
}

Anda secara alami akan mendapatkan banyak kondisi balapan, bagaimana jika utas lainnya dilakukan some_data = new_datatepat setelah Anda bangun, tetapi sebelum Anda melakukannyadata = some_data

Anda juga tidak dapat membuat mutex sendiri untuk menjaga kasus ini .eg

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);
}

Tidak akan bekerja, masih ada kemungkinan kondisi balapan di antara bangun dan meraih mutex. Menempatkan mutex sebelum pthread_cond_wait tidak membantu Anda, karena Anda sekarang akan memegang mutex sambil menunggu - yaitu produser tidak akan pernah bisa mengambil mutex. (perhatikan, dalam hal ini Anda dapat membuat variabel kondisi kedua untuk memberi sinyal pada produsen yang telah Anda selesaikan some_data- meskipun ini akan menjadi rumit, terutama jika Anda menginginkan banyak produsen / konsumen.)

Dengan demikian Anda memerlukan cara untuk melepaskan / mengambil mutex secara atom ketika menunggu / bangun dari kondisi tersebut. Itulah yang dilakukan variabel kondisi pthread, dan inilah yang akan Anda lakukan:

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);
}

(produsen tentu perlu mengambil tindakan pencegahan yang sama, selalu menjaga 'some_data' dengan mutex yang sama, dan memastikan itu tidak menimpa some_data jika some_data saat ini! = NULL)

tidak
sumber
Bukankah seharusnya while (some_data != NULL)loop do-while sehingga menunggu variabel kondisi setidaknya sekali?
Hakim Maygarden
3
Tidak. Apa yang Anda tunggu-tunggu, adalah agar 'some_data' menjadi non-null. Jika bukan nol "pertama kali", bagus, Anda memegang mutex dan dapat menggunakan data dengan aman. Jika Anda memiliki loop do / while, Anda akan melewatkan notifikasi jika seseorang memberi tanda variabel kondisi sebelum Anda menunggunya (itu tidak seperti peristiwa yang ditemukan pada win32 yang tetap ditandai sampai seseorang menunggu mereka)
no
4
Saya hanya tersandung pada pertanyaan ini dan terus terang, aneh untuk menemukan bahwa jawaban ini, yang hanya benar memiliki poin jauh lebih sedikit daripada jawaban paxdiablo yang memiliki kekurangan yang pasti (masih diperlukan atomisasi, diperlukan mutex hanya untuk menangani kondisi tersebut, bukan untuk menangani atau memberi tahu). Saya kira itulah cara kerja stackoverflow ...
stefaanv
@stefaanv, jika Anda ingin merinci kekurangannya, sebagai komentar atas jawaban saya, jadi saya melihatnya tepat waktu, daripada berbulan-bulan kemudian :-), saya akan dengan senang hati memperbaikinya. Ungkapan singkat Anda tidak benar-benar memberi saya cukup detail untuk mengetahui apa yang ingin Anda katakan.
paxdiablo
1
@nos, seharusnya tidak while(some_data != NULL)menjadi while(some_data == NULL)?
Eric Z
30

Variabel kondisi POSIX adalah stateless. Jadi itu adalah tanggung jawab Anda untuk mempertahankan negara. Karena status akan diakses oleh utas yang menunggu dan utas yang meminta utas lainnya berhenti menunggu, itu harus dilindungi oleh mutex. Jika Anda pikir Anda dapat menggunakan variabel kondisi tanpa mutex, maka Anda belum memahami bahwa variabel kondisi adalah stateless.

Variabel kondisi dibangun di sekitar suatu kondisi. Utas yang menunggu pada variabel kondisi sedang menunggu beberapa kondisi. Utas yang memberi sinyal kondisi variabel mengubah kondisi itu. Misalnya, utas mungkin sedang menunggu beberapa data tiba. Beberapa utas lainnya mungkin memperhatikan bahwa data telah tiba. "Data telah tiba" adalah kondisinya.

Inilah penggunaan klasik dari variabel kondisi, disederhanakan:

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
}

Lihat bagaimana utas menunggu pekerjaan. Pekerjaan dilindungi oleh mutex. Menunggu rilis mutex sehingga utas lain dapat memberikan utas ini beberapa pekerjaan. Berikut ini cara memberi isyarat:

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);
}

Perhatikan bahwa Anda memerlukan mutex untuk melindungi antrian kerja. Perhatikan bahwa variabel kondisi itu sendiri tidak tahu apakah ada pekerjaan atau tidak. Artinya, variabel kondisi harus dikaitkan dengan suatu kondisi, kondisi itu harus dipertahankan oleh kode Anda, dan karena itu dibagi di antara utas, itu harus dilindungi oleh mutex.

David Schwartz
sumber
1
Atau, untuk membuatnya lebih ringkas, seluruh titik variabel kondisi adalah untuk menyediakan operasi "buka dan tunggu" atom. Tanpa mutex, tidak akan ada yang bisa dibuka.
David Schwartz
Maukah Anda menjelaskan arti kewarganegaraan ?
snr
@ snr Mereka tidak memiliki status apa pun. Mereka tidak "terkunci" atau "ditandai" atau "tidak ditandai". Jadi, adalah tanggung jawab Anda untuk melacak keadaan apa pun yang terkait dengan variabel kondisi. Misalnya, jika variabel kondisi membuat utas tahu kapan antrian menjadi tidak kosong, itu harus menjadi kasus bahwa satu utas dapat membuat antrian tidak kosong dan beberapa utas lainnya perlu tahu kapan antrian menjadi tidak kosong. Itu adalah status bersama, dan Anda harus melindunginya dengan mutex. Anda dapat menggunakan variabel kondisi, terkait dengan kondisi bersama yang dilindungi oleh mutex, sebagai mekanisme bangun.
David Schwartz
16

Tidak semua fungsi variabel kondisi memerlukan mutex: hanya operasi menunggu yang melakukannya. Operasi sinyal dan siaran tidak memerlukan mutex. Variabel kondisi juga tidak secara permanen dikaitkan dengan mutex tertentu; mutex eksternal tidak melindungi variabel kondisi. Jika variabel kondisi memiliki keadaan internal, seperti antrian utas tunggu, ini harus dilindungi oleh kunci internal di dalam variabel kondisi.

Operasi menunggu menyatukan variabel kondisi dan mutex, karena:

  • thread telah mengunci mutex, mengevaluasi beberapa ekspresi atas variabel yang dibagi dan menemukan itu salah, sehingga perlu menunggu.
  • benang harus secara atomik bergerak dari memiliki mutex, ke menunggu kondisi tersebut.

Untuk alasan ini, operasi tunggu mengambil sebagai argumen baik mutex dan kondisi: sehingga dapat mengelola transfer atom dari thread dari memiliki mutex untuk menunggu, sehingga thread tidak menjadi korban dari kondisi lomba bangun yang hilang .

Kondisi perlombaan wakeup yang hilang akan terjadi jika sebuah thread memberikan mutex, dan kemudian menunggu objek sinkronisasi stateless, tetapi dengan cara yang tidak atom: ada jendela waktu ketika thread tidak lagi memiliki kunci, dan memiliki belum mulai menunggu objek. Selama jendela ini, utas lain dapat masuk, membuat kondisi yang ditunggu menjadi benar, memberi sinyal sinkronisasi tanpa kewarganegaraan dan kemudian menghilang. Objek stateless tidak ingat bahwa itu ditandai (stateless). Jadi, untaian asli tertidur pada objek sinkronisasi stateless, dan tidak bangun, meskipun kondisi yang diperlukan sudah menjadi kenyataan: kehilangan bangun.

Fungsi menunggu variabel kondisi menghindari bangun yang hilang dengan memastikan bahwa utas panggilan terdaftar untuk menangkap wakeup andal sebelum menyerah mutex. Ini tidak mungkin jika fungsi menunggu variabel kondisi tidak mengambil mutex sebagai argumen.

Kaz
sumber
Bisakah Anda memberikan referensi bahwa operasi siaran tidak perlu untuk mendapatkan mutex? Pada MSVC siaran diabaikan.
xvan
@ xvan POSIX pthread_cond_broadcastdan pthread_cond_signaloperasi (yang menjadi pertanyaan SO ini) bahkan tidak mengambil mutex sebagai argumen; hanya kondisinya. Spesifikasi POSIX ada di sini . Mutex hanya disebutkan sehubungan dengan apa yang terjadi di utas menunggu ketika mereka bangun.
Kaz
Maukah Anda menjelaskan arti kewarganegaraan ?
snr
1
@ snr Objek sinkronisasi stateless tidak ingat keadaan apa pun yang terkait dengan pensinyalan. Ketika diberi tanda, jika sesuatu menunggu sekarang, itu dibangunkan, jika tidak bangun akan dilupakan. Variabel kondisi tidak memiliki kewarganegaraan seperti ini. Keadaan yang diperlukan untuk membuat sinkronisasi dapat diandalkan dipertahankan oleh aplikasi dan dilindungi oleh mutex yang digunakan bersama dengan variabel kondisi, menurut logika yang ditulis dengan benar.
Kaz
7

Saya tidak menemukan jawaban lain yang ringkas dan mudah dibaca seperti halaman ini . Biasanya kode tunggu terlihat seperti ini:

mutex.lock()
while(!check())
    condition.wait()
mutex.unlock()

Ada tiga alasan untuk membungkus wait()dalam mutex:

  1. tanpa mutex utas lain bisa signal()sebelumwait() dan kami akan melewatkan ini bangun.
  2. biasanya check()tergantung pada modifikasi dari utas lain, jadi Anda tetap harus saling mengucilkan.
  3. untuk memastikan bahwa utas prioritas tertinggi berproses terlebih dahulu (antrian untuk mutex memungkinkan penjadwal untuk memutuskan siapa yang akan pergi berikutnya).

Poin ketiga tidak selalu menjadi perhatian - konteks historis ditautkan dari artikel ke percakapan ini .

Bangun palsu sering disebutkan sehubungan dengan mekanisme ini (yaitu utas menunggu dibangunkan tanpa signal()dipanggil). Namun, kejadian tersebut ditangani oleh yang diulang check().

Sam Brightman
sumber
4

Variabel kondisi dikaitkan dengan mutex karena itu adalah satu-satunya cara untuk menghindari perlombaan yang dirancang untuk dihindari.

// 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!

Pada titik ini, tidak ada utas yang akan memberi sinyal variabel kondisi, jadi utas1 akan menunggu selamanya, meskipun yang dilindungiReadyToRunVariable mengatakan siap untuk digunakan!

Satu-satunya cara untuk mengatasi hal ini adalah agar variabel kondisi melepaskan atom secara bersamaan sambil mulai menunggu variabel kondisi. Inilah sebabnya mengapa fungsi cond_wait membutuhkan 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);
Cort Ammon
sumber
3

Mutex seharusnya dikunci saat Anda menelepon pthread_cond_wait; ketika Anda menyebutnya secara atomic keduanya membuka mutex dan kemudian memblokir kondisi tersebut. Setelah kondisi diberi sinyal, secara atomis akan menguncinya lagi dan kembali.

Ini memungkinkan implementasi penjadwalan yang dapat diprediksi jika diinginkan, di mana utas yang akan melakukan pensinyalan dapat menunggu sampai mutex dilepaskan untuk melakukan pemrosesan dan kemudian memberi sinyal kondisi.

Amber
sumber
Jadi ... adakah alasan bagi saya untuk tidak meninggalkan mutex yang selalu tidak terkunci, lalu menguncinya tepat sebelum menunggu, dan kemudian membuka kuncinya tepat setelah menunggu selesai?
DAPAT DITERIMA
Mutex juga memecahkan beberapa ras potensial antara utas menunggu dan sinyal. selama mutex selalu terkunci ketika mengubah kondisi dan pensinyalan, Anda tidak akan pernah menemukan sinyal yang hilang dan tidur selamanya
Hasturkun
Jadi ... pertama - tama saya harus menunggu-on-mutex pada mutex conditionvar, sebelum menunggu di conditionvar? Saya tidak yakin saya mengerti sama sekali.
DAPAT DITERIMA
2
@elliottcable: Tanpa memegang mutex, bagaimana Anda bisa tahu apakah Anda harus menunggu atau tidak? Bagaimana jika apa yang Anda tunggu terjadi begitu saja ?
David Schwartz
1

Saya membuat latihan di kelas jika Anda ingin contoh nyata dari variabel kondisi:

#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);
}
Unit Berpikir Pusat
sumber
1

Tampaknya menjadi keputusan desain khusus daripada kebutuhan konseptual.

Menurut pthreads alasan mengapa mutex tidak dipisahkan adalah bahwa ada peningkatan kinerja yang signifikan dengan menggabungkan mereka dan mereka berharap bahwa karena kondisi balapan umum jika Anda tidak menggunakan mutex, itu hampir selalu akan dilakukan pula.

https://linux.die.net/man/3/pthread_cond_wait

Fitur Mutex dan Variabel Kondisi

Disarankan bahwa akuisisi dan pelepasan mutex dipisahkan dari kondisi menunggu. Ini ditolak karena itu adalah sifat gabungan dari operasi yang, pada kenyataannya, memfasilitasi implementasi realtime. Implementasi tersebut secara atomis dapat memindahkan utas prioritas tinggi antara variabel kondisi dan mutex dengan cara yang transparan bagi pemanggil. Ini dapat mencegah sakelar konteks tambahan dan menyediakan akuisisi mutex yang lebih deterministik ketika utas menunggu diberi sinyal. Dengan demikian, masalah keadilan dan prioritas dapat ditangani secara langsung oleh disiplin penjadwalan. Selanjutnya, operasi menunggu kondisi saat ini cocok dengan praktik yang ada.

Catskul
sumber
0

Ada banyak penafsiran tentang itu, namun saya ingin melambangkannya dengan contoh berikut.

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 }

Apa yang salah dengan cuplikan kode? Cukup renungkan sebelum melanjutkan.


Masalahnya benar-benar halus. Jika orang tua memanggil thr_parent()dan kemudian memeriksa nilainya done, ia akan melihat bahwa itu adalah 0dan dengan demikian mencoba untuk tidur. Tetapi sebelum panggilan menunggu untuk tidur, orang tua terganggu antara baris 6-7, dan anak berlari. Anak mengubah variabel status doneke 1dan sinyal, tetapi tidak ada utas menunggu dan dengan demikian tidak ada utas terbangun. Ketika orangtua berlari lagi, ia tidur selamanya, yang benar-benar mengerikan.

Bagaimana jika mereka dilakukan saat memperoleh kunci secara individual?

snr
sumber