Bagian Kritis dan Mutex bukan sistem operasi khusus, konsep multithreading/multiprocessing mereka.
Bagian Penting Merupakan bagian dari kode yang hanya boleh dijalankan sendiri pada waktu tertentu (misalnya, ada 5 utas yang berjalan secara bersamaan dan fungsi yang disebut "critical_section_function" yang memperbarui array ... Anda tidak ingin semua 5 utas memperbarui array sekaligus. Jadi ketika program menjalankan critical_section_function(), tidak ada thread lain yang harus menjalankan critical_section_function mereka.
mutex* Mutex adalah cara mengimplementasikan kode critical section (anggap saja seperti token... thread harus memilikinya untuk menjalankan critical_section_code)
Untuk Windows, bagian penting lebih ringan daripada mutex.
Mutex dapat dibagi antar proses, tetapi selalu menghasilkan panggilan sistem ke kernel yang memiliki beberapa overhead.
Bagian kritis hanya dapat digunakan dalam satu proses, tetapi memiliki keuntungan bahwa mereka hanya beralih ke mode kernel jika terjadi perselisihan - Perolehan yang tidak terbantahkan, yang seharusnya menjadi kasus umum, sangat cepat. Dalam kasus pertentangan, mereka memasuki kernel untuk menunggu beberapa primitif sinkronisasi (seperti peristiwa atau semaphore).
Saya menulis aplikasi sampel cepat yang membandingkan waktu antara keduanya. Di sistem saya untuk 1.000.000 akuisisi dan rilis yang tidak terbantahkan, mutex membutuhkan waktu lebih dari satu detik. Bagian kritis membutuhkan waktu ~50 md untuk 1.000.000 akuisisi.
Berikut kode pengujiannya, saya menjalankan ini dan mendapatkan hasil yang serupa jika mutex pertama atau kedua, jadi kami tidak melihat efek lainnya.
HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
CRITICAL_SECTION critSec;
InitializeCriticalSection(&critSec);
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER start, end;
// Force code into memory, so we don't see any effects of paging.
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
}
QueryPerformanceCounter(&end);
int totalTimeCS = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);
// Force code into memory, so we don't see any effects of paging.
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);
}
QueryPerformanceCounter(&end);
int totalTime = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);
printf("Mutex: %d CritSec: %d\n", totalTime, totalTimeCS);
Selain jawaban lainnya, detail berikut khusus untuk bagian penting di windows:
- jika tidak ada pertentangan, memperoleh bagian kritis semudah
InterlockedCompareExchange
operasi - struktur bagian kritis menampung ruang untuk mutex. Ini awalnya tidak terisi
- jika ada pertentangan antara utas untuk bagian kritis, mutex akan dialokasikan dan digunakan. Kinerja bagian kritis akan menurun ke mutex
- jika Anda mengantisipasi persaingan yang tinggi, Anda dapat mengalokasikan bagian penting yang menentukan jumlah putaran.
- jika ada pertentangan pada bagian kritis dengan jumlah putaran, utas yang mencoba mendapatkan bagian kritis akan berputar (menunggu-sibuk) selama siklus prosesor sebanyak itu. Ini dapat menghasilkan kinerja yang lebih baik daripada tidur, karena jumlah siklus untuk melakukan pengalihan konteks ke utas lain bisa jauh lebih tinggi daripada jumlah siklus yang diambil oleh utas pemilik untuk melepaskan mutex
- jika jumlah putaran berakhir, mutex akan dialokasikan
- ketika utas pemilik melepaskan bagian kritis, diperlukan untuk memeriksa apakah mutex dialokasikan, jika ya maka akan mengatur mutex untuk melepaskan utas menunggu
Di linux, menurut saya mereka memiliki "spin lock" yang memiliki tujuan yang mirip dengan bagian kritis dengan hitungan putaran.
Dari sudut pandang teoretis, bagian kritis adalah bagian kode yang tidak boleh dijalankan oleh beberapa utas sekaligus karena kode tersebut mengakses sumber daya bersama.
Mutex adalah algoritme (dan terkadang nama struktur data) yang digunakan untuk melindungi bagian penting.
Semafor dan Monitor adalah implementasi umum dari mutex.
Dalam prakteknya ada banyak implementasi mutex yang tersedia di windows. Mereka terutama berbeda sebagai konsekuensi dari penerapannya berdasarkan tingkat pengunciannya, cakupannya, biayanya, dan kinerjanya di bawah tingkat pertentangan yang berbeda. Lihat CLR Inside Out -Menggunakan konkurensi untuk skalabilitas untuk bagan biaya implementasi mutex yang berbeda.
Primitif sinkronisasi yang tersedia.
- Pantau
- Mutex
- Semafor
- ReaderWriterLock
- ReaderWriterLockSlim
- Bertautan
lock(object)
pernyataan diimplementasikan menggunakan Monitor
- lihat MSDN untuk referensi.
Dalam beberapa tahun terakhir banyak penelitian dilakukan pada sinkronisasi non-blocking. Tujuannya adalah untuk mengimplementasikan algoritme dengan cara bebas kunci atau bebas tunggu. Dalam algoritme semacam itu, suatu proses membantu proses lain untuk menyelesaikan pekerjaannya sehingga proses tersebut akhirnya dapat menyelesaikan pekerjaannya. Akibatnya suatu proses dapat menyelesaikan pekerjaannya bahkan ketika proses lain, yang mencoba melakukan beberapa pekerjaan, macet. Dengan menggunakan kunci, mereka tidak akan melepaskan kuncinya dan mencegah proses lain untuk melanjutkan.