Saya baru mengenal multithreading, dan berusaha memahami cara kerja mutex. Memang banyak Googling tetapi masih meninggalkan beberapa keraguan tentang cara kerjanya karena saya membuat program sendiri di mana penguncian tidak berfungsi.
Salah satu sintaks yang benar-benar non-intuitif dari mutex adalah pthread_mutex_lock( &mutex1 );
, di mana sepertinya mutex sedang dikunci, ketika apa yang ingin saya kunci adalah variabel lain. Apakah sintaksis ini berarti bahwa mengunci suatu mutex mengunci suatu wilayah kode sampai mutex tidak dikunci? Lalu bagaimana cara mengetahui bahwa wilayah tersebut dikunci? [ UPDATE: Utas tahu bahwa wilayah ini dikunci, oleh Memory Fencing ]. Dan bukankah fenomena seperti itu seharusnya disebut bagian kritis? [ UPDATE: Objek bagian kritis hanya tersedia di Windows, di mana objek lebih cepat daripada mutex dan hanya dapat dilihat oleh utas yang mengimplementasikannya. Jika tidak, bagian kritis hanya mengacu pada area kode yang dilindungi oleh mutex ]
Singkatnya, dapatkah Anda membantu dengan program contoh mutex yang paling sederhana dan penjelasan yang paling sederhana tentang logika cara kerjanya? Saya yakin ini akan membantu banyak pemula lainnya.
Jawaban:
Ini dia usaha sederhana saya untuk menjelaskan konsep ini kepada pemula di seluruh dunia: ( versi kode warna di blog saya juga)
Banyak orang berlari ke bilik telepon yang terpisah (mereka tidak memiliki ponsel) untuk berbicara dengan orang yang mereka cintai. Orang pertama yang menangkap gagang pintu stan, adalah orang yang diizinkan menggunakan telepon. Dia harus tetap memegang gagang pintu selama dia menggunakan telepon, kalau tidak orang lain akan memegang gagangnya, mengusirnya dan berbicara dengan istrinya :) Tidak ada sistem antrian seperti itu. Ketika orang itu selesai menelepon, keluar dari bilik dan meninggalkan pegangan pintu, orang berikutnya yang memegang gagang pintu akan diizinkan menggunakan telepon.
Sebuah benang adalah: Setiap orang
yang mutex adalah: Pintu menangani
The kunci adalah: Tangan seseorang
yang sumber daya adalah: Ponsel
Setiap utas yang harus menjalankan beberapa baris kode yang tidak boleh dimodifikasi oleh utas lain secara bersamaan (menggunakan telepon untuk berbicara dengan istrinya), harus terlebih dahulu mendapatkan kunci pada sebuah mutex (memegangi pegangan pintu bilik) ). Hanya dengan demikian sebuah utas dapat menjalankan jalur kode tersebut (melakukan panggilan telepon).
Setelah utas mengeksekusi kode itu, ia harus melepaskan kunci pada mutex sehingga utas lain dapat memperoleh kunci pada mutex (orang lain dapat mengakses bilik telepon).
[ Konsep memiliki mutex agak tidak masuk akal ketika mempertimbangkan akses eksklusif dunia nyata, tetapi di dunia pemrograman saya kira tidak ada cara lain untuk membiarkan utas lain 'melihat' bahwa utas sudah mengeksekusi beberapa baris kode. Ada konsep mutex rekursif dll, tetapi contoh ini hanya dimaksudkan untuk menunjukkan kepada Anda konsep dasar. Semoga contoh memberi Anda gambaran yang jelas tentang konsep tersebut. ]
Dengan C ++ 11 threading:
Kompilasi dan jalankan menggunakan
g++ -std=c++0x -pthread -o thread thread.cpp;./thread
Alih-alih menggunakan
lock
danunlock
, Anda dapat menggunakan tanda kurung seperti yang ditunjukkan di sini , jika Anda menggunakan kunci scoped untuk keuntungan yang diberikannya . Namun, scoped locks memiliki sedikit overhead kinerja.sumber
(could've shown scoped locking by not using acquire and release - which also is exception safe -, but this is clearer
. Sedangkan untuk menggunakan penguncian ruang lingkup, tergantung pada pengembang, tergantung pada jenis aplikasi yang mereka bangun. Jawaban ini dimaksudkan untuk mengatasi pemahaman dasar tentang konsep mutex dan tidak untuk masuk ke semua kompleksitasnya, jadi komentar dan tautan Anda disambut baik tetapi sedikit di luar cakupan tutorial ini.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
Bagian dalam dari fungsi ini terlihat sangat sederhana. Itu hanya satu pernyataan. Namun, bahasa padanan pseudo-assembly yang khas mungkin:
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:
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.
sumber
Tutorial utas terbaik yang saya tahu ada di sini:
https://computing.llnl.gov/tutorials/pthreads/
Saya suka itu ditulis tentang API, bukan tentang implementasi tertentu, dan memberikan beberapa contoh sederhana yang bagus untuk membantu Anda memahami sinkronisasi.
sumber
Saya menemukan posting ini baru-baru ini dan berpikir bahwa itu membutuhkan solusi yang diperbarui untuk perpustakaan standar c ++ 11 mutex (yaitu std :: mutex).
Saya telah menempelkan beberapa kode di bawah ini (langkah pertama saya dengan mutex - saya belajar concurrency pada win32 dengan HANDLE, SetEvent, WaitForMultipleObjects dll).
Karena ini adalah upaya pertama saya dengan std :: mutex dan teman-teman, saya ingin melihat komentar, saran, dan peningkatan!
sumber
Fungsi
pthread_mutex_lock()
dapat memperoleh mutex untuk utas panggilan atau memblokir utas sampai mutex dapat diperoleh. Yang terkaitpthread_mutex_unlock()
merilis mutex.Pikirkan tentang mutex sebagai antrian; setiap utas yang berupaya mendapatkan mutex akan ditempatkan di akhir antrian. Ketika utas melepaskan mutex, utas berikutnya dalam antrian terlepas dan sekarang berjalan.
Bagian kritis mengacu pada wilayah kode di mana non-determinisme dimungkinkan. Seringkali ini karena banyak utas berusaha mengakses variabel yang dibagi. Bagian kritis tidak aman sampai sinkronisasi dilakukan. Kunci mutex adalah salah satu bentuk sinkronisasi.
sumber
Anda seharusnya memeriksa variabel mutex sebelum menggunakan area yang dilindungi oleh mutex. Jadi pthread_mutex_lock Anda () dapat (tergantung pada implementasi) menunggu sampai mutex1 dilepaskan atau mengembalikan nilai yang menunjukkan bahwa kunci tidak dapat diperoleh jika orang lain telah menguncinya.
Mutex sebenarnya hanya sebuah semaphore yang disederhanakan. Jika Anda membaca tentang mereka dan memahaminya, Anda memahami mutex. Ada beberapa pertanyaan tentang mutex dan semaphore di SO. Perbedaan antara semaphore biner dan mutex , Kapan kita harus menggunakan mutex dan kapan kita harus menggunakan semaphore dan sebagainya. Contoh toilet di tautan pertama adalah contoh yang baik yang bisa dipikirkan orang. Semua kode dilakukan untuk memeriksa apakah kunci tersedia dan jika ada, cadangan. Perhatikan bahwa Anda tidak benar-benar memesan toilet itu sendiri, tetapi kuncinya.
sumber
pthread_mutex_lock
tidak dapat kembali jika orang lain memegang kunci. Memblokir dalam kasus ini dan itulah intinya.pthread_mutex_trylock
adalah fungsi yang akan kembali jika kunci dipegang.Bagi mereka yang mencari contoh mutex shortex:
sumber
CONTOH SEMAPHORE ::
Referensi: http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2008/Notes/threads-semaphores.txt
sumber