Muteks ve kritik bölüm arasındaki fark nedir?


134

Lütfen Linux'tan, Windows perspektifinden açıklayınız.

Ben C # programlıyorum, bu iki terim bir fark yaratır. Örnekler ve benzeri ile mümkün olduğunca çok posta gönderin ....

Teşekkürler

Yanıtlar:


232

Windows için kritik bölümler mutekslerden daha hafiftir.

Muteksler süreçler arasında paylaşılabilir, ancak her zaman bazı ek yükleri olan çekirdeğe sistem çağrısı ile sonuçlanır.

Kritik bölümler yalnızca bir işlem içinde kullanılabilir, ancak çekişme durumunda yalnızca çekirdek moduna geçmeleri avantajına sahiptir - Yaygın durum olması gereken sınırsız satın almalar inanılmaz derecede hızlıdır. Çekişme durumunda, bir senkronizasyon ilkelini (bir olay veya semafor gibi) beklemek için çekirdeğe girerler.

İkisi arasındaki süreyi karşılaştıran hızlı bir örnek uygulama yazdım. Sistemimde 1.000.000 sınırsız satın alma ve bırakma için bir muteks bir saniyeyi alır. Kritik bir bölüm 1.000.000 kazanım için ~ 50 ms sürer.

İşte test kodu, bunu çalıştırdım ve muteks birinci veya ikinci ise benzer sonuçlar aldım, bu yüzden başka efekt görmüyoruz.

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);

1
Bu ilgili olup olmadığından emin değilim (kodunuzu derlemediğimden ve denemediğimden), ancak WaitForSingleObject'i INFINITE ile çağırmanın düşük performansla sonuçlandığını gördüm. 1 zaman aşımı değerini ilettikten sonra dönüşünü kontrol ederken döngü yapmak bazı kodlarımın performansında büyük bir fark yarattı. Ancak bu çoğunlukla harici bir süreç tanıtıcısı beklemek bağlamındadır. YMMV. Muteks'in bu değişiklikle nasıl performans gösterdiğini görmek isterim. Bu testten ortaya çıkan zaman farkı, beklenenden daha büyük görünüyor.
Troy Howard

5
@TroyHoward sadece o noktada kilitlemeyi döndürmüyor musunuz?
dss539

Bu ayrımın nedenleri olasılıkla tarihseldir. Koşulsuz durumda CriticalSection kadar hızlı kilitleme uygulamak zor değildir (birkaç atomik talimat, sistem çağrısı yok), ancak süreçler boyunca (bir parça paylaşılan hafıza ile) çalışır. Bkz. Örneğin Linux futexes .
regnarg

2
@TroyHoward, CPU'nuzu her zaman% 100'de çalışmaya zorlamaya çalışın ve INFINITE'in daha iyi çalışıp çalışmadığını görün. Güç stratejisi, yavaşlamaya karar verdikten sonra makinemde (Dell XPS-8700) 40ms kadar sürebilir ve yavaşlamaya karar verdikten sonra tam hıza geri dönebilir;
Stevens Miller

Burada neyin gösterildiğini anladığımdan emin değilim. Genel olarak, kritik bir bölüme girmek bir çeşit semafor elde etmeyi gerektirir. Perde arkasında, O / S'nin bu kritik bölüm davranışını mutekslere ihtiyaç duymadan uygulamak için etkili bir yolu olduğunu mu söylüyorsunuz?
SN

89

Teorik bir bakış açısından, kritik bölüm , kod paylaşılan kaynaklara eriştiği için aynı anda birden fazla iş parçacığı tarafından çalıştırılmaması gereken bir kod parçasıdır.

Bir muteksin kritik bölümleri korumak için kullanılır (ve bazen veri yapısının adı) bir algoritmadır.

Semaforlar ve Monitörler bir muteksin ortak uygulamalarıdır.

Uygulamada, pencerelerde bulunan birçok muteks uygulaması vardır. Temel olarak uygulamalarının sonucu olarak kilitleme düzeyleri, kapsamları, maliyetleri ve farklı çekişme düzeylerindeki performansları nedeniyle farklılık gösterirler. Bkz. CLR Ters Yüz - Farklı muteks uygulamalarının maliyetlerinin bir çizelgesi için ölçeklenebilirlik için eşzamanlılığı kullanma .

Kullanılabilir senkronizasyon ilkeleri.

lock(object)İfadesi bir kullanılarak işletilir Monitor- bkz MSDN başvuru için.

Son yıllarda tıkanmasız senkronizasyon konusunda çok araştırma yapılmaktadır . Amaç algoritmaları kilitlemesiz veya beklemesiz bir şekilde uygulamaktır. Bu tür algoritmalarda, bir süreç diğer süreçlerin çalışmalarını bitirmesine yardımcı olur, böylece süreç sonunda çalışmasını bitirebilir. Sonuç olarak, bir süreç, bazı işler yapmaya çalışan diğer süreçler asılsa bile işini bitirebilir. Kilitler kullanıldığında, kilitlerini serbest bırakmazlar ve diğer işlemlerin devam etmesini önlerlerdi.


Kabul edilen cevabı görünce, yazdığınız Teorik Perspektifi görene kadar eleştirel bölümlerin kavramını yanlış hatırladığımı düşünüyordum . :)
Anirudh Ramanathan

2
Pratik kilitsiz programlama, mevcut olması dışında Shangri La gibidir. Keir Fraser'ın makalesi (PDF) bunu oldukça ilginç bir şekilde araştırıyor (2004'e dönecek). Ve 2012'de hala bununla mücadele ediyoruz.
Tim Post

22

Diğer yanıtlara ek olarak, aşağıdaki ayrıntılar pencerelerdeki kritik bölümlere özgüdür:

  • çekişmenin yokluğunda, kritik bir bölüm elde etmek bir InterlockedCompareExchangeoperasyon kadar basit
  • kritik bölüm yapısı bir muteks için yer tutar. Başlangıçta ayrılmamış
  • kritik bir bölüm için iş parçacıkları arasında çekişme varsa, muteks tahsis edilir ve kullanılır. Kritik bölümün performansı muteksinkine göre düşecektir
  • yüksek çekişme öngörüyorsanız, bir spin sayısı belirten kritik bölümü ayırabilirsiniz.
  • kritik bir bölüm üzerinde sıkma sayısı olan bir çekişme varsa, kritik bölümü elde etmeye çalışan iş parçacığı bu birçok işlemci döngüsü için dönecektir (meşgul-bekleme). Başka bir iş parçacığına bağlamsal geçiş yapmak için döngü sayısı muteksi serbest bırakmak için sahip olan iş parçacığının aldığı döngü sayısından çok daha yüksek olabileceğinden, bu durum uykudan daha iyi performans sağlayabilir.
  • sıkma sayısı sona ererse, muteks tahsis edilecektir
  • sahip olan iş parçacığı kritik bölümü serbest bıraktığında, muteksin tahsis edilip edilmediğini kontrol etmek gerekir, eğer öyleyse muteksi bekleyen bir iş parçacığını serbest bırakacak şekilde ayarlar

Linux'ta, kritik sayıya bir spin sayısıyla benzer bir amaca hizmet eden bir "spin kilidi" olduğunu düşünüyorum.


Maalesef, Pencere açısından kritik bir bölüm, çekirdek modunda gerçek kilitlemeli işlemden çok daha pahalı olan bir CAS işlemi yapmayı içerir . Ayrıca, Windows kritik bölümleri kendileriyle ilişkili spin sayılarına sahip olabilir.
Öner

2
Bu kesinlikle doğru değil. CAS, kullanıcı modunda cmpxchg ile yapılabilir.
Michael

InitializeCriticalSection çağırdıysanız varsayılan spin sayısı sıfır olduğunu düşündüm - bir spin sayısı uygulanmış istiyorsanız InitializeCriticalSectionAndSpinCount aramak zorunda. Bunun için bir referansınız var mı?
1800 BİLGİ

18

Kritik Bölüm ve Muteks İşletim sistemine özgü değildir, çok iş parçacığı / çok işlemli kavramları.

Kritik Bölüm , belirli bir zamanda yalnızca kendisi tarafından çalıştırılması gereken bir kod parçasıdır (örneğin, aynı anda çalışan 5 iş parçacığı ve bir diziyi güncelleyen "critical_section_function" adlı bir işlev vardır ... 5 iş parçacığının tümünü istemezsiniz Program kritik_section_function () çalıştırırken, diğer iş parçacıklarının hiçbirinin kritik_section_function işlevlerini çalıştırmaması gerekir.

mutex * Mutex, kritik bölüm kodunu uygulamanın bir yoludur (bir belirteç gibi düşünün ... thread'in kritik_seksiyon_kodunu çalıştırmak için buna sahip olması gerekir)


2
Ayrıca, muteksler süreçler arasında paylaşılabilir.
yapılandırıcı

14

Muteks, bir iş parçacığının edinebildiği ve diğer iş parçacıklarının onu almasını engelleyen bir nesnedir. Zorunlu değildir, tavsiye niteliğindedir; bir iş parçacığı muteksin temsil ettiği kaynağı edinmeden kullanabilir.

Kritik bir bölüm, işletim sistemi tarafından kesilmemesini garanti eden bir kod uzunluğudur. Sahte kodda şöyle olur:

StartCriticalSection();
    DoSomethingImportant();
    DoSomeOtherImportantThing();
EndCriticalSection();

1
Poster, karşılıklı dışlama sağlayan bir win32 Kritik bölüm nesnesi gibi kullanıcı modu senkronizasyon ilkellerinden bahsediyordu. Linux hakkında bir bilgim yok, ancak Windows çekirdeğinde sizin tanımladığınız gibi kritik bölgeler var - kesintisiz.
Michael

1
Neden reddedildiđini bilmiyorum. Doğru bir şekilde tanımladığınız, bir tür muteks olan CriticalSection adlı Windows çekirdek nesnesinden farklı olan kritik bir bölüm kavramı vardır . OP'nin ikinci tanım hakkında sorular sorduğuna inanıyorum.
Adam Rosenfield

En azından agnostik dil etiketi ile kafam karıştı. Ancak her durumda, Microsoft'un uygulamalarını temel sınıflarıyla aynı şekilde adlandırması için elde ettiğimiz şey budur. Kötü kodlama uygulaması!
Mikko Rantanen

Mümkün olduğunca fazla ayrıntı istedi ve özellikle Windows ve Linux'un kavramların iyi olduğu kulağına geldiğini söyledi. +1 - -1'i de anlamadı: /
Jason Coco

14

Linux'taki kritik seçime eşit olan 'hızlı' Windows , hızlı kullanıcı alanı muteksi anlamına gelen bir futex olacaktır . Bir futex ve mutex arasındaki fark, bir futex ile çekirdeğin yalnızca tahkim gerektiğinde dahil olması, böylece atom sayacı her değiştiğinde çekirdeğin konuşma yükünü kurtarmanızdır. Bu .. önemli bir tasarruf edebilirsiniz bazı uygulamalarda kilitleri müzakere zaman kazandırabilir.

Bir futeks, bir muteksi paylaşmak için kullanacağınız araçlar kullanılarak da süreçler arasında paylaşılabilir.

Ne yazık ki, futexlerin uygulanması çok zor olabilir (PDF). (2018 güncellemesi, 2009'daki kadar korkutucu değiller).

Bunun ötesinde, her iki platformda da hemen hemen aynı. Paylaşılan bir yapıda (umarım) açlığa neden olmayacak şekilde atomik, jetonla çalışan güncellemeler yapıyorsunuz. Geriye kalan sadece bunu gerçekleştirme yöntemidir.


6

Windows'da, kritik bir bölüm işleminizde yereldir. Bir muteks süreçler arasında paylaşılabilir / erişilebilir. Temel olarak, kritik bölümler çok daha ucuzdur. Özellikle Linux üzerinde yorum yapamıyorum, ancak bazı sistemlerde sadece aynı şey için takma adlar.


6

Sadece 2 sent eklemek için, kritik Bölümler bir yapı olarak tanımlanır ve üzerlerindeki işlemler kullanıcı modu bağlamında gerçekleştirilir.

ntdll! _RTL_CRITICAL_SECTION
   + 0x000 DebugInfo: Ptr32 _RTL_CRITICAL_SECTION_DEBUG
   + 0x004 LockCount: Int4B
   + 0x008 Özyineleme Sayısı: Int4B
   + 0x00c OwningThread: Ptr32 Geçersiz
   + 0x010 LockSemaphore: Ptr32 Geçersiz
   + 0x014 SpinCount: Uint4B

Muteks ise Windows nesne dizininde oluşturulan çekirdek nesneleridir (ExMutantObjectType). Muteks işlemleri çoğunlukla çekirdek kipinde gerçekleştirilir. Örneğin, bir Mutex oluştururken, çekirdekte nt! NtCreateMutant'ı çağırırsınız.


Mutex nesnesini başlatan ve kullanan bir program çöktüğünde ne olur? Mutex nesnesi otomatik olarak yer değiştirir mi? Hayır, söyleyebilirim. Sağ?
Ankur

6
Çekirdek nesnelerin bir referans sayısı vardır. Bir nesneye tanıtıcıyı kapatmak referans sayısını azaltır ve 0'a ulaştığında nesne serbest bırakılır. Bir işlem çöktüğünde, tüm tutamaçları otomatik olarak kapatılır, bu nedenle yalnızca bu işlemin tanıtıcısı olan bir muteks otomatik olarak yeniden konumlandırılır.
Michael

Kritik Kesit nesnelerinin işleme bağlı olmasının nedeni budur; öte yandan muteksler süreçler arasında paylaşılabilir.
Sisir

2

Michael'dan büyük cevap. C ++ 11'de tanıtılan muteks sınıfı için üçüncü bir test ekledim. Sonuç biraz ilginçtir ve hala tek işlemler için CRITICAL_SECTION nesnelerinin orijinal onayını desteklemektedir.

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);

Sonuçlarım 217, 473 ve 19 idi (son iki zamanın oranımın kabaca Michael'ınkiyle karşılaştırılabilir olduğunu, ancak makinem ondan en az dört yıl daha küçük olduğundan, 2009 ve 2013 arasında artan hızın kanıtını görebilirsiniz. , XPS-8700 çıktığında). Yeni muteks sınıfı, Windows muteksinin iki katıdır, ancak yine de Windows CRITICAL_SECTION nesnesinin onda birinden daha azdır. Sadece özyinelemesiz muteksi test ettiğimi unutmayın. CRITICAL_SECTION nesneleri özyinelemelidir (bir iş parçacığı aynı sayıda kalması koşuluyla bunları tekrar tekrar girebilir).


0

AC işlevlerine yalnızca gerçek parametrelerini kullanıyorsa reentrant denir.

Evresel işlevler aynı anda birden çok evre tarafından çağrılabilir.

Evresel işlev örneği:

int reentrant_function (int a, int b)
{
   int c;

   c = a + b;

   return c;
}

Evresel olmayan fonksiyon örneği:

int result;

void non_reentrant_function (int a, int b)
{
   int c;

   c = a + b;

   result = c;

}

C standart kitaplığı strtok () yeniden girilmez ve aynı anda 2 veya daha fazla iş parçacığı tarafından kullanılamaz.

Bazı platform SDK'ları, strtok_r () adlı strtok () 'un reentrant sürümü ile birlikte gelir;

Enrico Migliore

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.