Tolong jelaskan dari Linux, perspektif Windows?
Saya pemrograman dalam C #, apakah kedua istilah ini membuat perbedaan. Silakan memposting sebanyak mungkin, dengan contoh dan ....
Terima kasih
Tolong jelaskan dari Linux, perspektif Windows?
Saya pemrograman dalam C #, apakah kedua istilah ini membuat perbedaan. Silakan memposting sebanyak mungkin, dengan contoh dan ....
Terima kasih
Jawaban:
Untuk Windows, bagian-bagian penting lebih ringan dari pada mutex.
Mutex dapat dibagi antara 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 dalam kasus pertengkaran - Pengambilan yang tidak terkendali, yang seharusnya merupakan kasus umum, sangat cepat. Dalam kasus pertengkaran, mereka memasuki kernel untuk menunggu sinkronisasi primitif (seperti acara atau semaphore).
Saya menulis contoh aplikasi cepat yang membandingkan waktu antara keduanya. Pada sistem saya untuk 1.000.000 akuisisi dan rilis yang tidak dibiarkan, mutex membutuhkan waktu lebih dari satu detik. Bagian kritis membutuhkan ~ 50 ms untuk 1.000.000 akuisisi.
Inilah kode tes, 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);
Dari perspektif teoretis, bagian kritis adalah sepotong kode yang tidak boleh dijalankan oleh banyak utas sekaligus karena kode mengakses sumber daya bersama.
Sebuah mutex adalah sebuah algoritma (dan kadang-kadang nama struktur data) yang digunakan untuk melindungi bagian penting.
Semaphores dan Monitor adalah implementasi umum dari mutex.
Dalam praktiknya ada banyak implementasi mutex yang tersedia di windows. Mereka terutama berbeda sebagai konsekuensi dari implementasi mereka oleh tingkat penguncian mereka, cakupan mereka, biaya mereka, dan kinerja mereka di bawah berbagai tingkat pertikaian. Lihat CLR Inside Out - Menggunakan concurrency untuk skalabilitas untuk bagan biaya implementasi mutex yang berbeda.
Primitif sinkronisasi yang tersedia.
The lock(object)
pernyataan dilaksanakan menggunakan Monitor
- lihat MSDN untuk referensi.
Dalam beberapa tahun terakhir banyak penelitian yang dilakukan pada sinkronisasi non-blocking . Tujuannya adalah untuk mengimplementasikan algoritme dengan cara bebas kunci atau bebas menunggu. Dalam algoritma seperti itu suatu proses membantu proses lain untuk menyelesaikan pekerjaan mereka sehingga proses akhirnya dapat menyelesaikan pekerjaannya. Karena itu suatu proses dapat menyelesaikan pekerjaannya bahkan ketika proses lain, yang mencoba melakukan beberapa pekerjaan, hang. Gunakan kunci, mereka tidak akan melepaskan kunci mereka dan mencegah proses lainnya dari melanjutkan.
Selain jawaban lain, detail berikut khusus untuk bagian penting di windows:
InterlockedCompareExchange
operasiDi linux, saya pikir mereka memiliki "kunci putaran" yang melayani tujuan yang mirip dengan bagian kritis dengan jumlah putaran.
Critical Section dan Mutex tidak spesifik sistem operasi, konsep multithreading / multiprocessing.
Bagian Kritis Adalah sepotong 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 ini menjalankan critical_section_function (), tidak ada thread lain yang harus menjalankan critical_section_function mereka.
mutex * Mutex adalah cara mengimplementasikan kode bagian kritis (anggap saja seperti token ... utas harus memiliki itu untuk menjalankan critical_section_code)
Mutex adalah objek yang dapat diperoleh thread, mencegah utas lainnya mendapatkannya. Itu adalah nasihat, bukan wajib; sebuah thread dapat menggunakan sumber daya yang diwakili oleh mutex tanpa mendapatkannya.
Bagian kritis adalah panjang kode yang dijamin oleh sistem operasi untuk tidak diinterupsi. Dalam pseudo-code, itu akan seperti:
StartCriticalSection();
DoSomethingImportant();
DoSomeOtherImportantThing();
EndCriticalSection();
Windows 'fast' yang setara dengan pemilihan kritis di Linux akan menjadi futex , yang merupakan singkatan dari mutex ruang pengguna yang cepat. Perbedaan antara futex dan mutex adalah bahwa dengan futex, kernel hanya menjadi terlibat ketika arbitrasi diperlukan, sehingga Anda menghemat biaya bicara dengan kernel setiap kali penghitung atom diubah. Itu .. dapat menyimpan signifikan jumlah waktu kunci negosiasi dalam beberapa aplikasi.
Futex juga dapat dibagikan di antara proses, menggunakan cara yang Anda gunakan untuk berbagi mutex.
Sayangnya, futex bisa sangat sulit untuk diterapkan (PDF). (Pemutakhiran 2018, mereka hampir tidak menakutkan seperti pada 2009).
Selain itu, hampir sama di kedua platform. Anda membuat pembaruan atomik yang didorong token ke struktur bersama dengan cara yang (mudah-mudahan) tidak menyebabkan kelaparan. Yang tersisa hanyalah metode untuk mencapai itu.
Hanya untuk menambahkan 2 sen saya, Bagian kritis didefinisikan sebagai struktur dan operasi pada mereka dilakukan dalam konteks mode pengguna.
ntdll! _RTL_CRITICAL_SECTION + 0x000 DebugInfo: Ptr32 _RTL_CRITICAL_SECTION_DEBUG + 0x004 LockCount: Int4B + 0x008 RecursionCount: Int4B + 0x00c OwningThread: Ptr32 Void + 0x010 LockSemaphore: Ptr32 Void + 0x014 SpinCount: Uint4B
Sedangkan mutex adalah objek kernel (ExMutantObjectType) yang dibuat di direktori objek Windows. Operasi mutex sebagian besar diimplementasikan dalam mode kernel. Misalnya, saat membuat Mutex, Anda akhirnya memanggil nt! NtCreateMutant di kernel.
Jawaban yang bagus dari Michael. Saya telah menambahkan tes ketiga untuk kelas mutex yang diperkenalkan di C ++ 11. Hasilnya agak menarik, dan masih mendukung dukungan aslinya objek CRITICAL_SECTION untuk proses tunggal.
mutex m;
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);
// Force code into memory, so we don't see any effects of paging.
m.lock();
m.unlock();
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
m.lock();
m.unlock();
}
QueryPerformanceCounter(&end);
int totalTimeM = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);
printf("C++ Mutex: %d Mutex: %d CritSec: %d\n", totalTimeM, totalTime, totalTimeCS);
Hasil saya adalah 217, 473, dan 19 (perhatikan bahwa rasio waktu saya untuk dua terakhir kira-kira sebanding dengan Michael, tetapi mesin saya setidaknya empat tahun lebih muda darinya, sehingga Anda dapat melihat bukti peningkatan kecepatan antara 2009 dan 2013 , ketika XPS-8700 keluar). Kelas mutex baru dua kali lebih cepat dari mutex Windows, tetapi masih kurang dari sepersepuluh kecepatan objek Windows CRITICAL_SECTION. Perhatikan bahwa saya hanya menguji mutex non-rekursif. Objek CRITICAL_SECTION bersifat rekursif (satu utas dapat memasukkannya berulang kali, asalkan meninggalkan jumlah yang sama kali).
Fungsi AC disebut reentrant jika hanya menggunakan parameter aktualnya.
Fungsi reentrant dapat dipanggil oleh banyak utas secara bersamaan.
Contoh fungsi reentrant:
int reentrant_function (int a, int b)
{
int c;
c = a + b;
return c;
}
Contoh fungsi non reentrant:
int result;
void non_reentrant_function (int a, int b)
{
int c;
c = a + b;
result = c;
}
Strtok library C standar () tidak reentrant dan tidak dapat digunakan oleh 2 utas atau lebih pada saat yang sama.
Beberapa platform SDK dilengkapi dengan versi reentrant dari strtok () yang disebut strtok_r ();
Enrico Migliore