Sementara mutex dapat digunakan untuk memecahkan masalah lain, alasan utama mereka ada adalah untuk memberikan pengecualian bersama dan dengan demikian memecahkan apa yang dikenal sebagai kondisi ras. Ketika dua (atau lebih) utas atau proses berusaha mengakses variabel yang sama secara bersamaan, kami memiliki potensi untuk kondisi balapan. Pertimbangkan kode berikut
//somewhere long ago, we have i declared as int
void my_concurrently_called_function()
{
i++;
}
Bagian dalam dari fungsi ini terlihat sangat sederhana. Itu hanya satu pernyataan. Namun, bahasa padanan pseudo-assembly yang khas mungkin:
load i from memory into a register
add 1 to i
store i back into memory
Karena semua instruksi bahasa assembly yang setara diperlukan untuk melakukan operasi kenaikan pada i, kami mengatakan bahwa penambahan i adalah operasi non-atmoik. Operasi atom adalah operasi yang dapat diselesaikan pada perangkat keras dengan jaminan tidak akan terganggu begitu eksekusi instruksi telah dimulai. Bertambah i terdiri dari rantai 3 instruksi atom. Dalam sistem bersamaan di mana beberapa utas memanggil fungsi, masalah muncul ketika utas membaca atau menulis pada waktu yang salah. Bayangkan kita memiliki dua utas yang berjalan secara simultan dan satu memanggil fungsi segera setelah yang lainnya. Katakan juga bahwa kita telah menginisialisasi ke 0. Juga berasumsi bahwa kita memiliki banyak register dan bahwa dua utas menggunakan register yang sama sekali berbeda, sehingga tidak akan ada tabrakan. Waktu sebenarnya dari peristiwa ini mungkin:
thread 1 load 0 into register from memory corresponding to i //register is currently 0
thread 1 add 1 to a register //register is now 1, but not memory is 0
thread 2 load 0 into register from memory corresponding to i
thread 2 add 1 to a register //register is now 1, but not memory is 0
thread 1 write register to memory //memory is now 1
thread 2 write register to memory //memory is now 1
Apa yang terjadi adalah kita memiliki dua utas yang bertambah secara bersamaan, fungsi kita dipanggil dua kali, tetapi hasilnya tidak konsisten dengan fakta itu. Sepertinya fungsinya hanya dipanggil sekali. Ini karena atomisitasnya "rusak" pada tingkat mesin, artinya benang dapat saling mengganggu atau bekerja sama pada waktu yang salah.
Kami membutuhkan mekanisme untuk menyelesaikan ini. Kita perlu memaksakan pemesanan untuk instruksi di atas. Satu mekanisme umum adalah memblokir semua utas kecuali satu. Mutth pthread menggunakan mekanisme ini.
Utas apa pun yang harus menjalankan beberapa baris kode yang dapat secara tidak aman mengubah nilai bersama oleh utas lainnya pada saat yang sama (menggunakan telepon untuk berbicara dengan istrinya), pertama-tama harus dibuat mendapatkan kunci pada mutex. Dengan cara ini, utas apa pun yang memerlukan akses ke data bersama harus melewati kunci mutex. Hanya dengan demikian utas dapat mengeksekusi kode. Bagian kode ini disebut bagian kritis.
Setelah utas mengeksekusi bagian kritis, itu harus melepaskan kunci pada mutex sehingga utas lain dapat memperoleh kunci pada mutex.
Konsep memiliki mutex tampak agak aneh ketika mempertimbangkan manusia mencari akses eksklusif ke objek fisik nyata, tetapi ketika pemrograman, kita harus disengaja. Utas dan proses bersamaan tidak memiliki asuhan sosial dan budaya yang kita lakukan, jadi kita harus memaksa mereka untuk berbagi data dengan baik.
Jadi secara teknis, bagaimana cara kerja mutex? Bukankah itu menderita dari kondisi ras yang sama yang kami sebutkan sebelumnya? Bukankah pthread_mutex_lock () sedikit lebih rumit dari peningkatan variabel?
Secara teknis, kami membutuhkan dukungan perangkat keras untuk membantu kami. Perancang perangkat keras memberi kita instruksi mesin yang melakukan lebih dari satu hal tetapi dijamin atomik. Contoh klasik dari instruksi semacam itu adalah test-and-set (TAS). Ketika mencoba mendapatkan kunci pada sumber daya, kita mungkin menggunakan TAS mungkin memeriksa untuk melihat apakah nilai dalam memori adalah 0. Jika ya, itu akan menjadi sinyal kita bahwa sumber daya sedang digunakan dan kita tidak melakukan apa-apa (atau lebih akurat) , kita menunggu dengan beberapa mekanisme. Mutex pthreads akan menempatkan kita ke dalam antrian khusus dalam sistem operasi dan akan memberi tahu kita ketika sumber daya tersedia. Sistem Dumber mungkin mengharuskan kita untuk melakukan putaran putaran yang ketat, menguji kondisi berulang-ulang) . Jika nilai dalam memori bukan 0, TAS mengatur lokasi ke sesuatu selain 0 tanpa menggunakan instruksi lain. Itu' itu seperti menggabungkan dua instruksi perakitan menjadi 1 untuk memberi kita atomisitas. Dengan demikian, pengujian dan perubahan nilai (jika perubahan itu sesuai) tidak dapat terganggu setelah dimulai. Kita dapat membangun mutex di atas instruksi semacam itu.
Catatan: beberapa bagian mungkin terlihat mirip dengan jawaban sebelumnya. Saya menerima undangannya untuk mengedit, dia lebih suka dengan cara aslinya, jadi saya menjaga apa yang saya miliki yang diinfuskan dengan sedikit kata-katanya.