Mutex, çok iş parçacıklı sorunları çözmek için sıklıkla kullanılan bir programlama konseptidir. Topluma sorum:
Muteks nedir ve nasıl kullanılır?
Mutex, çok iş parçacıklı sorunları çözmek için sıklıkla kullanılan bir programlama konseptidir. Topluma sorum:
Muteks nedir ve nasıl kullanılır?
Yanıtlar:
İş yerinde büyük bir ısıtmalı tartışma yaparken, masamda böyle durumlar için tuttuğum bir lastik tavuk kullanıyorum. Tavuğu tutan kişi konuşmasına izin verilen tek kişidir. Tavuğu tutmazsan konuşamazsın. Yalnızca tavuğu istediğinizi belirtebilir ve konuşmadan önce onu elde edene kadar bekleyebilirsiniz. Konuşmayı bitirdiğinizde, tavuğu konuşmak için bir sonraki kişiye verecek olan moderatöre geri verebilirsiniz. Bu, insanların birbirleriyle konuşmalarını ve aynı zamanda kendi konuşma alanlarına sahip olmalarını sağlar.
Tavuğu Mutex ve iplikli kişi ile değiştirin ve temel olarak bir muteks kavramına sahipsiniz.
Tabii ki, kauçuk bir muteks diye bir şey yoktur. Sadece lastik tavuk. Kedilerimin bir zamanlar lastik bir faresi vardı, ama yediler.
Tabii ki, kauçuk tavuğu kullanmadan önce, kendinize bir odada 5 kişiye gerçekten ihtiyacınız olup olmadığını sormanız gerekir ve sadece odadaki bir kişi ile tüm işi kendi başına yapmak daha kolay olmaz. Aslında, bu sadece benzetmeyi genişletiyor, ama fikri anlıyorsunuz.
Mutex, birbirini dışlayan bir bayraktır. Bir iş parçacığının içeri girmesine ve diğerlerine erişiminin engellenmesine izin veren bir kod bölümüne kapı koruyucu görevi görür. Bu, kontrol edilen kodun aynı anda yalnızca tek bir iş parçacığına çarpmasını sağlar. İşiniz bittiğinde muteksi serbest bıraktığınızdan emin olun. :)
Karşılıklı dışlama. İşte Wikipedia girişi:
http://en.wikipedia.org/wiki/Mutual_exclusion
Muteksin amacı iki iş parçacığını eşitlemektir. Tek bir kaynağa erişmeye çalışan iki iş parçacığınız olduğunda, genel desen, kodu girmeden önce muteksi ayarlamak için ilk kod bloğuna erişmeye çalışır. İkinci kod bloğu erişmeye çalıştığında, muteksin ayarlandığını görür ve ilk kod bloğu tamamlanıncaya kadar bekler (ve muteksi çıkarır), sonra devam eder.
Bunun nasıl yapıldığına dair spesifik detaylar, programlama diline göre büyük ölçüde değişir.
Çok iş parçacıklı bir uygulamanız olduğunda, farklı iş parçacıkları bazen değişken veya benzeri gibi ortak bir kaynağı paylaşır. Bu paylaşılan kaynağa genellikle aynı anda erişilemez, bu nedenle bu kaynağı aynı anda yalnızca bir iş parçacığının kullandığından emin olmak için bir yapıya ihtiyaç vardır.
Bu kavram "karşılıklı dışlama" (kısa Mutex) olarak adlandırılır ve bu kaynağı kullanarak o alanın içinde yalnızca bir iş parçacığına izin verilmesini sağlamanın bir yoludur.
Bunların nasıl kullanılacağı dile özgüdür, ancak genellikle (her zaman olmasa da) bir işletim sistemi muteksine dayanır.
Bazı diller bu yapıya ihtiyaç duymaz, örneğin paradigma, örneğin fonksiyonel programlama (Haskell, ML iyi örneklerdir).
C # 'da kullanılan ortak muteks Monitör'dür . Tür ' System.Threading.Monitor ' tür. Ayrıca ' lock (Object) ' deyimi üzerinden dolaylı olarak da kullanılabilir . Bunun kullanımına bir örnek, bir Singleton sınıfı oluştururken verilebilir.
private static readonly Object instanceLock = new Object();
private static MySingleton instance;
public static MySingleton Instance
{
lock(instanceLock)
{
if(instance == null)
{
instance = new MySingleton();
}
return instance;
}
}
Özel kilit nesnesini kullanan lock deyimi kritik bir bölüm oluşturur. Her iş parçacığının bir önceki işin bitmesini beklemesini istemek İlk evre bölüme girecek ve örneği başlatacaktır. İkinci iş parçacığı bekleyecek, bölüme girecek ve başlatılan örneği alacaktır.
Statik bir elemanın her türlü senkronizasyonu lock deyimini benzer şekilde kullanabilir.
Bir nedir dışlama ?
Spineks olarak da bilinen muteks (Aslında, muteks terimi karşılıklı dışlama için kısadır), kritik bölgeleri korumak ve böylece yarış koşullarını önlemek için kullanılan en basit senkronizasyon aracıdır. Bir iş parçacığı, kritik bir bölüme girmeden önce bir kilit almalıdır (Kritik bölümde çoklu iş parçacıkları ortak bir değişkeni paylaşır, bir tabloyu güncelleştirir, bir dosya yazar vb.), Kritik bölümden ayrıldığında kilidi serbest bırakır.
Bir nedir yarışı Durumu ?
İki veya daha fazla iş parçacığı paylaşılan verilere erişebildiğinde ve aynı anda değiştirmeye çalıştıklarında bir yarış durumu oluşur. İş parçacığı zamanlama algoritması her zaman iş parçacıkları arasında geçiş yapabildiği için, iş parçacıklarının paylaşılan verilere erişmeye çalışacağı sırayı bilmiyorsunuz. Bu nedenle, veri değişikliğinin sonucu, iplik programlama algoritmasına bağlıdır, yani her iki iplik de verilere erişmek / verileri değiştirmek için "yarışır".
Gerçek hayat örneği:
İş yerinde büyük bir ısıtmalı tartışma yaparken, masamda böyle durumlar için tuttuğum bir lastik tavuk kullanıyorum. Tavuğu tutan kişi konuşmasına izin verilen tek kişidir. Tavuğu tutmazsan konuşamazsın. Yalnızca tavuğu istediğinizi belirtebilir ve konuşmadan önce onu elde edene kadar bekleyebilirsiniz. Konuşmayı bitirdiğinizde, tavuğu konuşmak için bir sonraki kişiye verecek olan moderatöre geri verebilirsiniz. Bu, insanların birbirleriyle konuşmalarını ve aynı zamanda kendi konuşma alanlarına sahip olmalarını sağlar.
Tavuğu Mutex ve iplikli kişi ile değiştirin ve temel olarak bir muteks kavramına sahipsiniz.
@Xetius
C # 'de kullanım:
Bu örnek, korumalı bir kaynağa erişimi eşitlemek için yerel bir Mutex nesnesinin nasıl kullanıldığını gösterir. Her çağrı iş parçacığı mutex'in sahipliğini alana kadar engellendiğinden, iş parçacığının sahipliğini serbest bırakmak için ReleaseMutex yöntemini çağırmalıdır.
using System;
using System.Threading;
class Example
{
// Create a new Mutex. The creating thread does not own the mutex.
private static Mutex mut = new Mutex();
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
{
// Create the threads that will use the protected resource.
for(int i = 0; i < numThreads; i++)
{
Thread newThread = new Thread(new ThreadStart(ThreadProc));
newThread.Name = String.Format("Thread{0}", i + 1);
newThread.Start();
}
// The main thread exits, but the application continues to
// run until all foreground threads have exited.
}
private static void ThreadProc()
{
for(int i = 0; i < numIterations; i++)
{
UseResource();
}
}
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
Console.WriteLine("{0} is requesting the mutex",
Thread.CurrentThread.Name);
mut.WaitOne();
Console.WriteLine("{0} has entered the protected area",
Thread.CurrentThread.Name);
// Place code to access non-reentrant resources here.
// Simulate some work.
Thread.Sleep(500);
Console.WriteLine("{0} is leaving the protected area",
Thread.CurrentThread.Name);
// Release the Mutex.
mut.ReleaseMutex();
Console.WriteLine("{0} has released the mutex",
Thread.CurrentThread.Name);
}
}
// The example displays output like the following:
// Thread1 is requesting the mutex
// Thread2 is requesting the mutex
// Thread1 has entered the protected area
// Thread3 is requesting the mutex
// Thread1 is leaving the protected area
// Thread1 has released the mutex
// Thread3 has entered the protected area
// Thread3 is leaving the protected area
// Thread3 has released the mutex
// Thread2 has entered the protected area
// Thread2 is leaving the protected area
// Thread2 has released the mutex
Burada bazı harika cevaplar var, işte muteksin ne olduğunu açıklamak için başka bir harika benzetme :
Anahtarlı tekli tuvaleti düşünün . Birisi girdiğinde anahtarı alır ve tuvalet işgal edilir . Başka birinin tuvaleti kullanması gerekiyorsa, kuyrukta beklemesi gerekir . Tuvaletteki kişi bittiğinde , anahtarı sıradaki bir sonraki kişiye geçirirler. Mantıklı, değil mi?
Dönüştürme tuvalet bir hikayenin içinde paylaşılan kaynağın ve anahtarın bir karşı Muteksleri . Anahtarı tuvalete götürmek (bir kilit almak) onu kullanmanıza izin verir. Anahtar yoksa (kilit kilitli) beklemeniz gerekir. Anahtar kişi tarafından iade edildiğinde ( kilidi serbest bırakın ) şimdi almakta özgürsünüz.
Önce MUTEX'i anlamak için "yarış koşulu" nun ne olduğunu bilmeniz gerekir ve sonra MUTEX'in neden gerekli olduğunu yalnızca siz anlarsınız. Çok iş parçacıklı bir programınız olduğunu ve iki iş parçacığınızın olduğunu varsayalım. Şimdi, iş kuyruğunda bir işiniz var. İlk iş parçacığı iş kuyruğunu kontrol eder ve işi bulduktan sonra yürütmeye başlar. İkinci iş parçacığı ayrıca iş kuyruğunu kontrol eder ve kuyrukta bir iş olduğunu bulur. Böylece, aynı iş işaretçisini de atayacaktır. Şimdi ne oluyor, her iki iş parçacığı da aynı işi yapıyor. Bu bir segmentasyon hatasına neden olacaktır. Bu bir yarış koşulu örneğidir.
Bu sorunun çözümü MUTEX'tir. MUTEX her seferinde bir dişi kilitleyen bir çeşit kilittir. Başka bir evre onu kilitlemek isterse, evre bloke olur.
Bu pdf dosya bağlantısındaki MUTEX konusu gerçekten okumaya değer.
Mutex: Mutex Mut ual Ex anlamına gelir * ını. Bir seferde bir işlem / iş parçacığının kritik bölüme girebileceği anlamına gelir. Birden çok iş parçacığının / işlemin paylaşılan kaynağı güncellemeye çalıştığı eşzamanlı programlamada (herhangi bir değişken, paylaşılan bellek vb.) Beklenmedik sonuçlara yol açabilir. (Sonuç, hangi iş parçacığının / işlemin ilk erişimi alacağına bağlıdır).
Böyle beklenmedik bir sonuçtan kaçınmak için, bir seferde yalnızca bir iş parçacığının / işlemin bu tür bir kaynağa erişmesini sağlayan bazı senkronizasyon mekanizmasına ihtiyacımız var.
pthread kütüphanesi Mutex için destek sağlar.
typedef union
{
struct __pthread_mutex_s
{
***int __lock;***
unsigned int __count;
int __owner;
#ifdef __x86_64__
unsigned int __nusers;
#endif
int __kind;
#ifdef __x86_64__
short __spins;
short __elision;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
# define __PTHREAD_SPINS 0, 0
#else
unsigned int __nusers;
__extension__ union
{
struct
{
short __espins;
short __elision;
# define __spins __elision_data.__espins
# define __elision __elision_data.__elision
# define __PTHREAD_SPINS { 0, 0 }
} __elision_data;
__pthread_slist_t __list;
};
#endif
Bu muteks veri tipinin yapısıdır, yani pthread_mutex_t. Muteks kilitlendiğinde, __lock 1 olarak ayarlanır. Kilidi açıldığında __lock 0 olarak ayarlanır.
Bu, kritik işleme aynı anda iki işlemin / iş parçacığının erişememesini sağlar.