C++ iyi performans, yüksek hassasiyet ve yeterli bellek yönetim sistemi ile en hızlı programlama dillerinden biri olarak bilinir. Bu programlama dili ayrıca, aralarında birden çok kaynağın paylaşılmasıyla birden çok iş parçacığının eşzamanlı yürütülmesini de destekler. Çoklu iş parçacığında, iş parçacığı yalnızca, iş parçacığı diğer iş parçacıklarının o sırada yaptıklarından etkilenmediği için sorun yaratmayan okuma işlemini gerçekleştirmek içindir. Ancak bu iş parçacıkları kaynakları aralarında paylaşmak zorundaysa, bir iş parçacığı o anda sorunu oluşturan verileri değiştirebilir. Bu sorunla başa çıkmak için, nesneye/koda erişimin aynı anda yalnızca bir iş parçacığına sağlanabileceğini belirten senkronizasyonu sağlayarak kodumuza/nesnemize birden fazla kaynağın erişimini engelleyen C++ “Mutex”imiz var, böylece birden çok iş parçacığı bu nesneye aynı anda erişemez.
Prosedür:
Muteks kilidi kullanarak bir nesneye birden çok iş parçacığının erişimini tek seferde nasıl durdurabileceğimizi öğreneceğiz. Mutex kilidinin sözdiziminden, çoklu iş parçacığı oluşturmanın ne olduğundan ve muteks kilidini kullanarak çoklu iş parçacığı oluşturmanın neden olduğu sorunlarla nasıl başa çıkabileceğimizden bahsedeceğiz. Ardından, çoklu iş parçacığına bir örnek alacağız ve üzerlerine mutex kilidini uygulayacağız.
Sözdizimi:
Nesnemize veya kodumuza aynı anda birden fazla iş parçacığının erişimini engellemek için mutex kilidini nasıl uygulayabileceğimizi öğrenmek istiyorsak, aşağıdaki sözdizimini kullanabiliriz:
$ std :: muteks mut_x
$mut_x. kilit ( ) ;
işlev_adı geçersiz kıl ( ) {
$ // birden fazla thread'den gizlemek istediğimiz kod buraya yazılacak
$mut_x. kilidini açar ( ) ;
}
Şimdi, bu sözdizimini aşağıda belirtildiği gibi tam olarak nasıl kullanabileceğimizi size bildirmek için sahte örnekte ve sözde kodda (kod düzenleyicide olduğu gibi çalıştıramayacağımız) bu sözdizimini kullanacağız:
$ std :: muteks mut_x
boşluk bloğu ( ) {
$mut_x. kilit ( ) ;
$ std :: cout << 'merhaba' ;
$mut_x. kilidini açar ( ) ;
}
Örnek:
Bu örnekte, önce multithread işlemini oluşturmaya çalışalım ve ardından işlemin oluşturulan kod veya nesneye senkronizasyonunu sağlamak için bu işlemi mutex lock ve unlock ile çevreleyelim. Mutex, oldukça öngörülemeyen değerler olan ve zaman bilinçli iş parçacıklarının geçişine bağlı olan yarış koşullarıyla ilgilenir. Mutex örneğini uygulamak için önce önemli ve gerekli kitaplıkları depolardan içe aktarmamız gerekir. Gerekli kütüphaneler şunlardır:
$ #
$ #
$ #
“iostream” kütüphanesi bize verileri Cout olarak görüntüleme, verileri Cin olarak okuma ve ifadeyi endl olarak sonlandırma işlevi sağlar. İpliklerdeki programları veya işlevleri kullanmak için “thread” kitaplığını kullanırız. 'Mutex' kitaplığı, kodda hem mutex kilidini hem de kilidini açmamızı sağlar. “# include” kullanıyoruz çünkü bu, kodda bulunan kitaplıkla ilgili tüm programlara izin veriyor.
Şimdi, bir önceki adım tamamlandıktan sonra, std'yi kullanarak muteks için mutex sınıfını veya global bir değişkeni tanımlıyoruz. Ardından, kodda daha sonra arayabileceğimiz mutex lock ve unlock için bir fonksiyon oluşturuyoruz. Bu örnekte bu fonksiyonu blok olarak adlandırıyoruz. Block fonksiyonunun gövdesinde önce “mutex.lock()”u çağırıyoruz ve kodun mantığını yazmaya başlıyoruz.
mutex.lock(), oluşturulan nesneye veya koda ulaşmak için diğer iş parçacıklarının erişimini reddeder, böylece aynı anda yalnızca bir iş parçacığı nesnemizi okuyabilir. Mantıkta 0'dan 9'a kadar index üzerinde çalışan bir for döngüsü çalıştırıyoruz. Döngüdeki değerleri görüntülüyoruz. İşlemi yapıldıktan sonra veya mantıktan çıktıktan sonra mutex kilidinde bu mantık oluşturulduktan sonra “mutex.unlock()” yöntemini çağırırız. Bu yöntem çağrısı, nesnenin tek bir iş parçacığına erişimi daha önce ve o nesne üzerindeki işlem bir kerede bir iş parçacığı tarafından yapıldığında, oluşturulan nesneyi muteks kilidinden açmamızı sağlar. Artık diğer iş parçacıklarının da bu nesneye veya koda erişmesini istiyoruz. Aksi takdirde, kodumuz muteks ile oluşturulan nesnenin sonsuza kadar kilitli durumda kalmasına neden olan “kilitlenme” durumunda hareket eder ve başka hiçbir iş parçacığı bu nesneye erişemez. Bu nedenle, tamamlanmamış bir işlem yürütülmeye devam eder. Bundan sonra blok fonksiyonundan çıkıp ana fonksiyona geçiyoruz.
Ana olarak, thread1, thread2 ve thread3, vb. adlarla “std :: thread thread_name (burada muteks yarattığımız zaten oluşturulmuş blok işlevini çağırarak)” kullanarak üç thread oluşturarak oluşturduğumuz muteksimizi görüntüleriz. Bu şekilde, üç iş parçacığı oluşturulur. Daha sonra aynı anda yürütülecek bu üç thread'i “thread_name. birleştirme ()” yöntemi. Ve sonra, sıfıra eşit değeri döndürürüz. Örneğin daha önce bahsedilen açıklaması, aşağıdaki şekilde gösterilebilecek kod biçiminde uygulanmaktadır:
Kodun çıktısında, her üç iş parçacığının tek tek yürütülmesini ve görüntülenmesini görebiliriz. Uygulamamızın multithreading kategorisine girip girmediğini görebiliriz. Yine de, 'işlev bloğu' muteksinin uygulanması nedeniyle iş parçacıklarının hiçbiri verilerin üzerine yazmadı veya verileri değiştirmedi ve değiştirilen kaynağı paylaşmadı.
Çözüm
Bu kılavuz, C++'da kullanılan muteks işlevi kavramının ayrıntılı bir açıklamasını verir. Multithreading uygulamalarının neler olduğunu, multithreading uygulamalarında hangi problemlerle karşılaşmamız gerektiğini ve multithreading uygulamaları için neden mutex'i uygulamamız gerektiğini tartıştık. Daha sonra sözde kodu kullanarak yapay örnekle muteksin sözdizimini tartıştık. Ardından, C++ görsel stüdyosunda mutex ile çoklu iş parçacığı uygulamaları üzerinde eksiksiz bir örnek uyguladık.