Pertanyaan Dalam situasi apa Anda menggunakan semaphore melalui mutex di C ++?


Sepanjang sumber daya yang sudah saya baca tentang multithreading, mutex lebih sering digunakan dan didiskusikan dibandingkan dengan semaphore. Pertanyaan saya adalah kapan Anda menggunakan semaphore atas mutex? Saya tidak melihat semaphores di thread Boost. Apakah itu berarti semaphores tidak lagi banyak digunakan belakangan ini?

Sejauh yang saya mengerti, semaphores memungkinkan sumber daya untuk dibagikan oleh beberapa utas. Ini hanya mungkin jika benang itu hanya membaca sumber daya tetapi tidak menulis. Apakah ini benar?


32
2018-02-28 08:47


asal


Jawaban:


Boost.Thread memiliki variabel mutexes dan condition. Murni dalam hal fungsi, semaphores karenanya redundan [*], meskipun saya tidak tahu apakah itu sebabnya mereka dihilangkan.

Semaphore adalah primitif yang lebih mendasar, lebih sederhana, dan mungkin diimplementasikan menjadi lebih cepat, tetapi tidak memiliki penghindaran inversi prioritas. Mereka bisa dibilang lebih sulit untuk digunakan daripada variabel kondisi, karena mereka membutuhkan kode klien untuk memastikan bahwa jumlah posting "cocok" dengan jumlah menunggu dalam beberapa cara yang tepat. Dengan variabel kondisi mudah untuk mentoleransi posting palsu, karena tidak ada yang benar-benar tidak apa saja tanpa memeriksa kondisinya.

Membaca vs menulis sumber adalah IMO herring merah, itu tidak ada hubungannya dengan perbedaan antara mutex dan semaphore. Jika Anda menggunakan penghitungan semafor, Anda bisa memiliki situasi di mana beberapa utas secara bersamaan mengakses sumber daya yang sama, dalam hal ini mungkin harus akses hanya-baca. Dalam situasi itu, Anda mungkin bisa menggunakannya shared_mutex dari Boost.Thread sebagai gantinya. Tapi semaphores tidak "untuk" melindungi sumber daya dengan cara mutex, mereka "untuk" mengirim sinyal dari satu utas ke yang lain. Itu mungkin untuk menggunakan mereka untuk mengontrol akses ke sumber daya.

Itu tidak berarti bahwa semua penggunaan semaphore harus berhubungan dengan sumber daya read-only. Misalnya, Anda dapat menggunakan semaphore biner untuk melindungi sumber baca / tulis. Mungkin tidak menjadi ide yang baik, karena mutex sering memberi Anda perilaku penjadwalan yang lebih baik.

[*] Berikut ini secara kasar bagaimana Anda menerapkan penghitungan semafor menggunakan mutex dan variabel condition. Untuk menerapkan semaphore bersama tentu saja Anda memerlukan mutex / condvar bersama:

struct sem {
    mutex m;
    condvar cv;
    unsigned int count;
};

sem_init(s, value)
    mutex_init(s.m);
    condvar_init(s.cv);
    count = value;

sem_wait(s)
    mutex_lock(s.m);
    while (s.count <= 0) {
        condvar_wait(s.cv, s.m);
    }
    --s.count;
    mutex_unlock(s.m);

sem_post(s)
    mutex_lock(s.m);
    ++s.count;
    condvar_broadcast(s.cv)
    mutex_unlock(s.m);

Oleh karena itu, apa pun yang dapat Anda lakukan dengan semaphore, Anda dapat melakukannya dengan variabel mutex dan condition. Belum tentu dengan benar-benar menerapkan semaphore.


4
2018-02-28 15:32



Kasus penggunaan yang khas untuk mutex (memungkinkan hanya satu akses thread ke sumber daya setiap saat) jauh lebih umum daripada penggunaan umum jika semaphore. Tapi semaphore sebenarnya adalah konsep yang lebih umum: Mutex adalah (hampir) kasus khusus semaphore.

Aplikasi yang umum adalah: Anda tidak ingin membuat lebih dari (mis.) 5 koneksi basis data. Tidak peduli berapa banyak pekerja thread yang ada, mereka harus berbagi 5 koneksi ini. Atau, jika Anda menjalankan pada mesin N-core, Anda mungkin ingin memastikan bahwa tugas-tugas CPU / memori-intensif tertentu tidak berjalan di lebih dari N thread pada saat yang sama (karena itu hanya akan mengurangi throughput karena switch konteks dan efek cache thrashing). Anda bahkan mungkin ingin membatasi jumlah CPU / memori tugas-tugas intensif paralel untuk N-1, sehingga sisa sistem tidak kelaparan. Atau bayangkan tugas tertentu membutuhkan banyak memori, jadi menjalankan lebih dari N misalnya dari tugas itu pada saat yang sama akan mengarah ke paging. Anda bisa menggunakan semaphore di sini, untuk memastikan bahwa tidak lebih dari N instance dari tugas khusus ini dijalankan pada saat yang bersamaan.

EDIT / PS: Dari pertanyaan Anda "Ini hanya mungkin jika benang itu hanya membaca sumber daya tetapi tidak menulis. Apakah ini benar?" dan komentar Anda, tampaknya bagi saya seolah-olah Anda berpikir tentang sumber daya sebagai variabel atau aliran, yang dapat dibaca atau ditulis dan itu hanya dapat ditulis oleh satu utas pada satu waktu. Jangan. Ini menyesatkan dalam konteks ini.

Pikirkan sumber daya seperti "air". Anda bisa menggunakan air untuk mencuci piring Anda. Saya bisa menggunakan air untuk mencuci piring saya pada saat yang sama. Kami tidak memerlukan sinkronisasi apa pun untuk itu, karena ada cukup air untuk kami berdua. Kami tidak selalu menggunakannya sama air. (Dan Anda tidak bisa "membaca" atau "menulis" air.) Tapi jumlah total air terbatas. Jadi itu tidak mungkin apa saja jumlah pihak untuk mencuci piring mereka pada saat yang bersamaan. Sinkronisasi semacam ini dilakukan dengan semaphore. Hanya biasanya tidak dengan air tetapi dengan sumber daya terbatas lainnya seperti memori, ruang disk, throughput IO atau core CPU.


18
2018-02-28 09:25



Inti dari perbedaan antara mutex dan semafor ada hubungannya dengan konsep kepemilikan. Ketika sebuah mutex diambil, kita berpikir tentang thread itu sebagai pemilik mutex dan thread yang sama harus kemudian melepaskan mutex kembali untuk melepaskan sumber daya.

Untuk semafor, pikirkan mengambil semaphore sebagai mengkonsumsi sumber daya, tetapi tidak benar-benar mengambil kepemilikan itu. Ini biasanya disebut sebagai semaphore yang "kosong" daripada dimiliki oleh utas. Fitur semafor kemudian adalah bahwa benang yang berbeda dapat "mengisi" semaphore kembali ke keadaan "penuh".

Oleh karena itu, mutex biasanya digunakan untuk perlindungan konkurensi sumber daya (yaitu: Pengecualian MUTual) sementara semaphore digunakan untuk menandakan antara benang (seperti tanda bendera semaphore antara kapal). Mutex dengan sendirinya tidak dapat digunakan untuk signaling, tetapi semaphores bisa. Jadi, memilih salah satu dari yang lain tergantung pada apa yang Anda coba lakukan.

Lihat yang lain salah satu jawabanku di sini untuk diskusi lebih lanjut tentang topik terkait yang mencakup perbedaan antara mutex rekursif dan non-rekursif.


11
2018-02-28 17:12



Untuk mengontrol akses ke sejumlah sumber daya yang terbatas yang dibagikan oleh beberapa utas (baik antar-atau intra-proses).

Dalam aplikasi kami, kami memiliki sumber daya yang sangat berat dan bahwa kami tidak ingin mengalokasikan satu untuk masing-masing benang pekerja M. Karena benang pekerja membutuhkan sumber daya hanya untuk satu bagian kecil dari pekerjaan mereka, kami jarang menggunakan lebih dari beberapa sumber daya secara bersamaan.

Jadi, kami mengalokasikan N dari sumber daya itu dan menempatkan mereka di belakang semaphore yang diinisialisasi ke N. Ketika lebih banyak lagi N thread mencoba menggunakan sumber daya, mereka hanya akan memblokir sampai satu tersedia.


9
2018-02-28 08:58



Saya merasa seperti tidak ada cara sederhana untuk melakukannya SANGAT jawab pertanyaan Anda tanpa mengabaikan beberapa informasi penting tentang semaphore. Orang telah menulis banyak buku tentang semaphores, jadi jawaban satu atau dua paragraf adalah merugikan. Sebuah buku populer Buku Kecil Semaphore... bagi mereka yang tidak suka buku-buku besar :).

Ini lumayan artikel yang panjang yang masuk ke BANYAK detail tentang bagaimana semaphore digunakan dan bagaimana mereka dimaksudkan untuk digunakan.

Memperbarui:
Dan menunjukkan beberapa kesalahan dalam contoh saya, saya akan meninggalkannya dengan referensi yang menawarkan penjelasan JAUH lebih baik dari saya :).

Berikut adalah referensi yang menunjukkan cara KANAN seseorang harus menggunakan semafor:
1. Artikel IBM
2. Kuliah Universitas Chicago
3. Artikel Netrino yang saya posting.
4. Kertas "jual tiket" + kode. 


3
2018-02-28 09:40



Seperti yang diambil dari artikel ini:

Sebuah mutex memungkinkan sinkronisasi antar-proses terjadi. Jika Anda memberi contoh mutex dengan nama (seperti pada kode di atas), mutex menjadi sistem-lebar. Ini sangat berguna jika Anda berbagi pustaka yang sama di antara banyak aplikasi yang berbeda dan perlu memblokir akses ke bagian kritis kode yang mengakses sumber daya yang tidak dapat dibagikan.

Akhirnya, kelas Semaphore. Katakanlah Anda memiliki metode yang benar-benar intensif CPU, dan juga memanfaatkan sumber daya yang Anda perlukan untuk mengontrol akses ke (menggunakan Mutexes :)). Anda juga telah menetapkan bahwa maksimum lima panggilan ke metode adalah tentang semua mesin Anda dapat hanlde tanpa membuatnya tidak responsif. Solusi terbaik Anda di sini adalah memanfaatkan kelas Semaphore yang memungkinkan Anda membatasi sejumlah akses thread ke sumber daya.


1
2018-02-28 10:40



Sejauh yang saya mengerti semaphores adalah istilah terkait IPC yang kuat akhir-akhir ini. Ini masih berarti variabel yang dilindungi banyak proses dapat dimodifikasi, tetapi di antara proses dan fitur ini didukung oleh OS.

Biasanya, kita tidak memerlukan variabel dan mutex sederhana mencakup semua persyaratan kami. Jika kita masih membutuhkan variabel, mungkin, kita kode itu sendiri - "variabel + mutex" untuk mendapatkan kontrol lebih banyak.

Resume: kami tidak menggunakan semaphore dalam multithreading karena biasanya menggunakan mutex untuk kesederhanaan dan kontrol, dan kami menggunakan semaphores untuk IPC karena ini didukung OS dan nama resmi untuk proses mekanisme sinkronisasi.


0
2018-02-28 09:28



Semaphores awalnya dipahami untuk sinkronisasi di seluruh proses. Windows menggunakan WaitForMultipleObjects yang seperti semafor. Di dunia linux, implementasi pthread awal tidak memungkinkan mutex untuk dibagikan lintas proses. Sekarang mereka melakukannya. Konsep memecah pertambahan atom (peningkatan bertautan di Windows) bersama dengan mutex ringan adalah implementasi paling praktis hari ini setelah thread menjadi unit penjadwalan untuk cpu. Jika kenaikan dan kunci disatukan (semafor), waktu untuk mendapatkan / melepaskan kunci akan terlalu panjang dan kita tidak dapat membagi 2 fungsi unit seperti yang kita lakukan hari ini untuk kinerja dan konstruksi sinkronisasi yang lebih baik.


0
2018-01-20 17:22