Makarna (Spagetti) Yiyen Düşünürler Problemi
En eğlenceli bilgisayar problemlerinden biridir.
N adet düşünür bir masanın etrafına oturmuştur.
Bunlar yeterince düşündükten sonra acıkırlar.
Her birinin önünde birer tabak makarna vardır.
Tüm tabakların arasında da birer çatal bulunmaktadır.
Dolayısıyla N adet makarna tabağı ve N adet çatal vardır.
Düşünürler ne yazık ki iki çatal kullanmadan makarna yiyememektedir.
Dolayısıyla yan yana oturan iki düşünür aynı anda makarna yiyememektedir.
N kişilik bir masada en fazla tamsayı ( N/2 ) adet düşünür yemek yiyebilir.
Düşünürlerimizin hiçbiri aç kalmayacak şekilde, düşünürlerin hayatları bilgisayar ortamında nasıl modellenmelidir?
HATALI ÇÖZÜM
proses düşünür ( i : integer )
{
while ( true ) do
düşün ( );
çatal_al ( i );
çatal_al ( (i+1) mod N );
ye ( );
çatal_bırak ( i );
çatal_bırak ( (i+1) mod N );
end while
}
Herbir düşünür yukarıdaki şekilde düşünürse oluşabilecek problemi görebildiniz mi?
Öyle bir an gelebilir ki, her düşünür sadece çatal_al ( i ); komutunu çalıştırabilir.
Bu durumda her biri sağ eline çatalı alabilecek, diğer eli boş kalacaktır.
Dolayısıyla, her biri açlıktan ölebilir :) Kimse çatalını bırakmıyor.
Sonuç: Ölümcül Kilitlenme
DOĞRU ÇÖZÜM
Elimizdeki düşünürler sadece 3 işlem yapmaktadırlar.
Hayatlarını durum geçiş diyagramı ile gösterelim:
Birbirleriyle aynı anda bazı işlemleri yapamamaları sağlanmalıdır.
Semafor: İşletim sistemi desteği ile karşılıklı dışlamanın çözüldüğü yapı.
Kritik bölgeye girişi P ( sem ), çıkışı ise V ( sem ) ifade etsin.
durum [ 1...N ] // her düşünürün durumu
sem_dışla = 1 // kritik bölgeye tek girişi garantiler
sem_izin [ 1...N ] // kullanıcıların kullanım izni
proses düşünür ( i : integer )
{
while ( true ) do
düşün ( );
çatal_al ( i );
ye ();
çatal_bırak ( i );
end while
}
proses çatal_al ( i : integer )
{
begin
P ( sem_dışla );
durum [ i ] = "aç"
dene ( i );
V ( sem_dışla );
P ( sem_izin [ i ] ); // semaforun değeri 1 olmalı ki askıya alınmasın
end
}
proses dene ( i : integer )
{
var sağ, sol : integer;
begin
sağ = ( i + N - 1 ) mod N;
sol = ( i + 1 ) mod N;
if(durum [ i ] == "aç" and durum [ sol ] <> "ye" and durum [ sağ ] <> "ye")
V ( sem_izin [ i ] );
end
}
proses çatal_bırak ( i : integer )
{
var sağ, sol : integer;
begin
sağ = ( i + N - 1 ) mod N;
sol = ( i + 1 ) mod N;
P ( sem_dışla );
durum [ i ] = "düşün"
dene ( sol ); // solumdaki arkadaş için çatalı ele geçirmeyi deniyorum
dene ( sağ ); // sağımdaki arkadaş için çatalı ele geçirmeyi deniyorum
V ( sem_dışla );
end
}
İlginç bir çalışma: Karşılıklı Dışlama (Tek Sayfalık Makale)