Evet arkadaşlar, şimdi bu ders videosunda, bazı gerçekçi örneklerin yardımıyla koşul değişkeni ve muteks
kullanımını uygulayalım.
Şimdi, bu örnekte, tüketici iş parçacığı olarak adlandırılan bir T1 iş parçacığım olduğunu ve üretici iş parçacığı
olarak adlandırılan bir T2 iş parçacığım olduğunu görebilirsiniz.
Doğru.
Ve bazı veri yapılarımız var.
Bu veri yapısının hiçbir şey olmadığını, sadece bazı veri öğeleri içeren bir kuyruk olduğunu
ve T1 iş parçacığı ile T2 tehdidinin bu veri yapısına erişmek için birbirleriyle rekabet ettiğini varsayalım.
Doğru.
Şimdi, T1 tehdidi bir tüketici iş parçacığı olduğundan, bu sadece T1 iş parçacığının bu kuyruktan bir
öğeyi çıkarmak ve doğru şekilde işlemek istediği anlamına gelir.
T2 iş parçacığı ise bir üretici tehdididir ve bazı veriler üretir ve bu verileri bu kuyruğa iter.
Doğru.
Bu nedenle t1 iş parçacığı bu kuyruğu tüketirken, t2 iş parçacığı bu kuyruğa daha fazla veri besler.
Bu nedenle t2 iş parçacığı üretici iş parçacığı olarak adlandırılırken, t1 iş parçacığı tüketici iş parçacığı olarak adlandırılır.
Artık bir veri yapımız var.
Q iş parçacıkları arasında paylaşılan bir veri kaynağıdır.
Şimdi, bu veri yapısı üzerinde karşılıklı dışlama sağlamak için, bu veri yapısının
kendisiyle ilişkili bir mutex nesnesine sahip olması ve ayrıca koşul değişkenine sahip olması gerekir.
Koşul değişkeni, tüketici ve üretici iş parçacıklarını senkronize etmek için kullanılır.
Doğru.
Mutex nesnesinin ve koşul değişkenlerinin veri yapısının özellikleri olduğunu unutmayın.
Koşul değişkeninin veri yapısı yerine bir iş parçacığının özelliği haline geldiği bazı küçük
sapmalar olsa da.
Ancak konuyu basit tutmak için bu koşulla devam edelim.
Değişken ve muteksler.
Her ikisi de kaynağın özellikleridir.
Değil mi?
Şimdi, örneği açıkladıktan sonra, T1 ve T2 iş parçacığının bu veri yapısından bir öğeyi hem ürettiği hem de tükettiği
adımların üzerinden geçeceğiz.
Birbirini dışlayan bir şekilde sıraya koyun.
Değil mi?
Ve bunun için her iki iş parçacığı da bu koşul değişkenini ve muteksi kullanır.
Yani arkadaşlar, sorunumuz şu: T1 iş parçacığı kuyruktan bir öğeyi kaldırmaya çalıştığında,
öğeyi engellenmeden kuyruktan başarıyla kaldırıyor.
Doğru.
Elbette t1 iş parçacığının kuyruğa yalnızca kuyruk iş parçacığı tarafından kullanılmadığında erişmesi gerekir.
T2.
Doğru.
Ancak d bir tehdidi kuyruktan bir eleman çıkarmaya çalışırsa ancak kuyruk zaten boşsa, bu durumda tüketici
iş parçacığımız engellenmeli ve bir üretici iş parçacığı olan D iki iş parçacığı kuyruğa yeni
bir eleman itene kadar engellenmiş olarak kalmalıdır.
Doğru.
İşte çözmeye çalıştığımız sorun ifadesi budur.
Ve daha ünlü olarak, bu problem ifadesine üretici Tüketici problemi denir.
Dolayısıyla sorun ifadesi, T1 iş parçacığının kuyruktan bir öğeyi kaldırmaya çalışması ve kuyruğun
zaten boş durumda olması halinde engellenmesi gerektiği konusunda açıktır.
Doğru.
Ve tüketici iş parçacığının, üretici iş parçacığı bir öğe üretip kuyruğa itene kadar bloke
kalması beklenir.
Doğru.
Şimdi bu mantığı uygulamak için koşul değişkenleri muteksleri ve yüklemlerin nasıl bir araya gelebileceğini
adım adım görelim.
Şimdi yüklem, karşılaştığınız yeni bir terimdir.
Yüklemin tam olarak ne olduğunu açıklayacağım.
Öncelikle tüketici konusuyla başlayalım.
Değil mi?
Dolayısıyla, tüketici iş parçacığının yapması gereken ilk şey, bir kuyruk olan paylaşılan kaynak üzerinde
bir kilit elde etmektir, değil mi?
Unutmayın, kuyruk paylaşılan bir kaynaktır ve her iki iş parçacığı da bu paylaşılan kaynağa erişim
talep ederken karşılıklı dışlama kuralına uymalıdır.
Bu nedenle, tüketici iş parçacığının bu kuyruk üzerinde herhangi bir işlem gerçekleştirebilmesi için öncelikle bu kuyruğa kilitlenmesi
gerekir.
Şimdi de T1 ipliğini varsayalım.
Bu kuyruk üzerinde kilit elde edebilir.
T1 iş parçacığının yapacağı bir sonraki şey bu kuyruktan bir öğe tüketmektir.
Doğru.
Ve t1 iş parçacığı bu kuyruktaki öğeyi yalnızca kuyruk boş olmadığında tüketebilmelidir.
Yani basitçe, kuyruk boşsa tüketici iş parçacığının engellenmesi gerektiği anlamına gelir.
Doğru.
Bunu S2 numaralı adımda görebilirsiniz.
Tüketici iş parçacığı kaynağın durumunu test ediyor.
Bu, kuyruğun boş olup olmadığıdır.
Dolayısıyla, kaynağın durumunu kontrol etmek anlamına gelen S2 adımını özel olarak gerçekleştirmek.
İş parçacığı tarafından kaynağın durumunu kontrol etmek için kullanılan koşul teknik olarak yüklem olarak adlandırılır.
Yani bu koşula yüklem denir.
Yani iş parçacığı senkronizasyonu dünyasında kullanılan teknik bir terimdir ve yüklem, iş parçacığının
kaynağın durumunu test ettiği koşulu temsil eder.
Dolayısıyla, S2 numaralı adımın tüketici iş parçacığı tarafından özel olarak gerçekleştirilmesi için S1 adımı gereklidir, yani muteksin
kilitlenmesi gerekir.
Şimdi bu muteksin neden gerekli olduğunu anlıyorsunuz, değil mi?
Böylece iş parçacığı kaynağın durumunu kontrol ederken iş parçacığı kaynağın durumunu özel olarak kontrol
edebilir.
Sürecin başka hiçbir iş parçacığı kaynağın durumunu değiştirmemelidir.
İşte bu nedenle adım numarasında muteks kilitleme gereklidir.
S1 ve yüklem, iş parçacığına beklemesi gerekip gerekmediğini söyleyen bir koşuldur.
Doğru.
Bu örnekte, S2 numaralı adım koşulu test etmektedir ve teknik olarak bu koşul yüklem olarak adlandırılmaktadır.
Şimdi, tüketici iş parçacığının kuyruğu boş olarak bulduğunu, yani tüketici iş parçacığının tüketecek
hiçbir şeyi olmadığını varsayarsak, tüketici iş parçacığının engellenmesi gerekir ve üçüncü adımda bir API
p iş parçacığı koşulunu çağırmamızın nedeni budur.
Problem ifadesi uyarınca tüketici iş parçacığını bloke etmek için bekleyin, üretici iş parçacığı öğeyi
boş kuyruğa itene kadar tüketici iş parçacığımızın bloke kalmasını istiyoruz.
Yani burada, bekleme koşulu doğruysa, yani kuyruk boşsa.
Tüketici iş parçacıklarımız üçüncü adımda koşul değişkenini kullanarak kendini bloke eder.
Doğru.
Şimdi üçüncü adımda, tüketici iş parçacığı engellenmiş durumda, değil mi?
Yani tüketici iş parçacığı şimdi üretici iş parçacığının bir öğe üretmesini ve kuyruğa itmesini
bekliyor.
Yani bu basitçe, üretici ipliğinin artık resme gireceği anlamına geliyor.
Şimdi üretici iş parçacığının kuyruğa bir öğe itmesi gerekiyor.
Bu, üretici iş parçacığının paylaşılan bir kaynak üzerinde yazma işlemi gerçekleştirdiği anlamına gelir.
Değil mi?
Bu da basitçe, üretici iş parçacığının da paylaşılan kaynak kuyruğuna karşılıklı olarak özel bir erişime ihtiyaç duyduğu anlamına
gelir.
Ve bu nedenle üretici iş parçacığı muteksin kilitlenmesi ile başlar.
Doğru.
Tüketici iş parçacığının üçüncü adımda blok durumunda olduğunu unutmayın.
Bu muteksin perde arkasında kilidinin açıldığını zaten biliyoruz ve bu muteksin kilidi açıldığı
için üretici iş parçacığı artık altıncı adımda bu muteks üzerindeki kilidi ele geçirebilir.
Şimdi bir üretici iş parçacığı kuyruğun dolu olup olmadığını test edecektir.
Doğru, bu yedi numaralı adımda, üretici iş parçacığı bir öğe üretebilir ve onu kuyruğa itebilir.
Yani bu özel eylem, paylaşılan bir kaynak üzerinde gerçekleştirilen bir yazma işlemini temsil ediyor, değil mi?
Başka bir deyişle, burası kritik bölümdür ve üretici iş parçacığı öğeyi başarılı bir şekilde kuyruğa ittikten sonra,
üretici iş parçacığının tüketici iş parçacığına sinyal göndererek tüketici iş parçacığına "hey, tüketici
iş parçacığı, kuyruğa bir öğe yerleştirdim" diye bildirdiğini görebilirsiniz.
İnfazına devam edebilirsin, değil mi?
Böylece sekiz numaralı adım üretici iş parçacığı tarafından yürütüldükten sonra.
Bu koşul değişkenine bir sinyal gönderilecektir.
Doğru.
Dolayısıyla T2 tehdidi, yani üretici tehdidi, adım numarasındaki kaynak durumunu kontrol eder.
S7 S6 numaralı adımda ayrıcalık sözü verirken yeni elemanı üretir ve kuyruğa
alır.
Ardından üretici tehdit S8 numaralı adımda tüketici tehdide sinyal gönderir ve S9 numaralı
adımda üretici tehdit muteksin kilidini açar.
Tamam, bu API kilidini açmak.
Sekiz numaralı adımdan hemen sonra ve dokuz numaralı adımdan önce, tüketici iş parçacığının engellenmiş durumdan yürütmeye
hazır duruma geçtiğini, ancak tüketici iş parçacığının dört numaralı adımı yalnızca üretici iş
parçacığı muteksin kilidini başarıyla açtığında yürüteceğini unutmayın.
Bu dokuzuncu adım.
Yalnızca dokuz numaralı adımdan sonra, tüketici iş parçacığı gerçekten yürütülmeye başlar.
Dolayısıyla, dördüncü adımda, tüketici iş parçacığı yürütmeye devam eder etmez, bu muteks üzerindeki kilit işletim
sistemi tarafından dahili olarak tüketici iş parçacığına verilir.
Doğru.
Ve bu nedenle sadece.
Tüketici iş parçacığı bu kuyruk üzerinde işlem gerçekleştirebilir.
Yani, artık bu kuyruktan bir öğe tüketebilir.
Dolayısıyla S4 numaralı adım, tüketici iş parçacığının uyandırıldığında yürüttüğü kritik bölümdür.
Doğru.
Ve son olarak, tüketici iş parçacığı kuyruktan bir öğe tüketirken işi bittiğinde, tüketici iş parçacığı
muteksin kilidini açabilir.
Değil mi?
Bu yüzden beşinci adımda, işiniz bittiğinde paylaşılan verilerin kilidini açıkça açın.
Peki tüm bu hikayede, kritik bölümü temsil eden adımlar nelerdir diye soracak olursam, basitçe tanımdan
yola çıkarak kritik bölüm, paylaşılan kaynağa eriştiğimiz kod parçasıdır.
Dolayısıyla, üretici tarafındaki bu belirli kod bölgesi kritik bölümdür.
Ve tüketici tarafındaki bu belirli kod bölgesi kritik bölüm, değil mi?
Tüm bu hikayeyi analiz ederseniz, herhangi bir zamanda tüketici ve üretici ipliğinin karşılıklı dışlama
ilkesine uyduğunu göreceksiniz.
Değil mi?
Bir kez daha yinelemek gerekirse, bu muteksin rolü, rekabet halindeki iş parçacıklarının paylaşılan kaynağa karşılıklı
olarak özel erişime sahip olmalarını sağlamaktır; bu koşul değişkeninin rolü ise kaynak için rekabet
eden iş parçacıkları arasında koordinasyona izin vermektir.
Doğru.
Bu koşul değişkeni sayesinde tüketici iş parçacığı kendini bloke edebilmiş ve üretici iş parçacığı
koşul değişkenine sinyal gönderebilmiştir.
Doğru.
Ayrıca şimdi S1'den S9'a kadar olan adım sayısını tamamladık ve eksik adım sayısı
olan S2, S4 ve S7'yi tamamladık.
Şu andan itibaren, iş parçacığı senkronizasyonunun en zor kısmı olan koşul değişkeni ve mutekslerle
çalışmakla uğraşıyorsunuz.
Doğru.
Muteksleri ve koşul değişkenlerini nasıl kullanacağınızı net bir şekilde anladıktan sonra, iş parçacığı senkronizasyonu
için kullanılan monitor, semaforlar gibi daha karmaşık ve sofistike veri yapılarını uygulayabileceksiniz.
Şimdi bu kod parçalarında, bir sonraki ders videosunda tartışacağımız bir iyileştirme
kapsamımız var.