Mengutip halaman manual:
Saat menggunakan variabel kondisi selalu ada predikat Boolean yang melibatkan variabel bersama yang terkait dengan setiap kondisi, tunggu itu benar jika utas harus dilanjutkan. Wakeups palsu dari fungsi pthread_cond_timedwait () atau pthread_cond_wait () dapat terjadi. Karena pengembalian dari pthread_cond_timedwait () atau pthread_cond_wait () tidak menyiratkan apa-apa tentang nilai predikat ini, predikat harus dievaluasi kembali setelah pengembalian tersebut.
Jadi, pthread_cond_wait
dapat kembali bahkan jika Anda belum mengisinya. Setidaknya pada pandangan pertama, itu tampak sangat mengerikan. Ini akan seperti fungsi yang secara acak mengembalikan nilai yang salah atau secara acak dikembalikan sebelum benar-benar mencapai pernyataan pengembalian yang tepat. Sepertinya bug utama. Tetapi fakta bahwa mereka memilih untuk mendokumentasikan ini di halaman manual daripada memperbaikinya tampaknya menunjukkan bahwa ada alasan yang sah mengapa pthread_cond_wait
akhirnya bangun dengan palsu. Agaknya, ada sesuatu yang intrinsik tentang cara kerjanya yang membuatnya sehingga tidak dapat membantu. Pertanyaannya adalah apa.
Mengapa tidak pthread_cond_wait
kembali spuriously? Mengapa tidak bisa menjamin bahwa itu hanya akan bangun ketika sudah diberi sinyal dengan benar? Adakah yang bisa menjelaskan alasan perilakunya yang palsu?
pthread_cond_(timed)wait
: "Jika sinyal dikirim ... utas melanjutkan menunggu variabel kondisi seolah-olah itu adalah tidak terputus, atau akan mengembalikan nol karena bangun palsu ". Fungsi pemblokiran lain menunjukkanEINTR
ketika terganggu oleh sinyal (misalnyaread
), atau diminta untuk melanjutkan (misalnyapthread_mutex_lock
). Jadi jika tidak ada alasan lain untuk bangun palsu,pthread_cond_wait
bisa didefinisikan seperti salah satu dari itu.Jawaban:
Penjelasan berikut diberikan oleh David R. Butenhof dalam "Programming with POSIX Threads" (hlm. 80):
Dalam diskusi comp.programming.threads berikut , ia memperluas pemikiran di balik desain:
sumber
Setidaknya ada dua hal 'bangun palsu' bisa berarti:
pthread_cond_wait
dapat kembali dari panggilan meskipun tidak ada panggilan kepthread_call_signal
ataupthread_cond_broadcast
pada kondisi yang terjadi.pthread_cond_wait
balasannya karena panggilan kepthread_cond_signal
ataupthread_cond_broadcast
, namun setelah mendapatkan kembali mutex, predikat yang mendasarinya ternyata tidak lagi benar.Tetapi kasus terakhir dapat terjadi bahkan jika implementasi variabel kondisi tidak memungkinkan kasus sebelumnya. Pertimbangkan antrean konsumen produsen, dan tiga utas.
pthread_cond_wait
, dan blokir dalam panggilan menunggu sinyal / siaran.Jadi karena Anda sudah selalu perlu memeriksa predikat di bawah satu lingkaran, tidak ada bedanya jika variabel kondisi yang mendasari dapat memiliki jenis lain dari bangun palsu.
sumber
pthread_cond_signal/broadcast
dan Anda tidak akan dapat melakukannya, sampai mutex dibuka dengan meneleponpthread_cond_wait
.Bagian "Kebangkitan Berganda oleh Sinyal Kondisi" di pthread_cond_signal memiliki contoh implementasi pthread_cond_wait dan pthread_cond_signal yang melibatkan wakekup palsu.
sumber
Sementara saya tidak berpikir itu dianggap pada saat desain, berikut adalah alasan teknis sebenarnya: Dalam kombinasi dengan pembatalan ulir, ada beberapa kondisi di mana mengambil opsi untuk membangunkan "secara palsu" mungkin benar-benar diperlukan, setidaknya kecuali Anda Bersedia memberikan batasan yang sangat kuat pada strategi implementasi seperti apa yang mungkin.
Masalah utama adalah bahwa, jika sebuah thread bekerja pada pembatalan saat diblokir
pthread_cond_wait
, efek sampingnya haruslah seolah-olah tidak mengkonsumsi sinyal apa pun pada variabel kondisi. Namun, sulit (dan sangat membatasi) untuk memastikan bahwa Anda belum mengkonsumsi sinyal ketika Anda mulai bertindak pada pembatalan, dan pada tahap ini mungkin tidak mungkin untuk "memposting ulang" sinyal ke variabel kondisi, karena Anda mungkin berada dalam situasi di mana peneleponpthread_cond_signal
sudah dibenarkan telah menghancurkan condvar dan membebaskan memori di mana ia tinggal.Penyisihan untuk bangun palsu memberi Anda jalan keluar yang mudah. Alih-alih terus bertindak atas pembatalan ketika tiba sementara diblokir pada variabel kondisi, jika Anda mungkin telah mengkonsumsi sinyal (atau jika Anda ingin malas, tidak peduli apa), Anda dapat mendeklarasikan bahwa peringatan palsu telah terjadi sebagai gantinya, dan kembali dengan sukses. Ini sama sekali tidak mengganggu operasi pembatalan, karena penelepon yang benar hanya akan bertindak pada pembatalan yang tertunda saat berikutnya ia mengulang dan menelepon
pthread_cond_wait
lagi.sumber