Evet arkadaşlar, şimdi size joinable kavramını ve iş parçacıklarını gösteren demo programını
göstereyim.
Bu yüzden Multithreading Bible slash thread basics slash joinable dizinindeyim.
Ve bu dizinin içinde Joinable Example dot c Right dosyasını bulacaksınız.
İşte bu dosyayı tartışacağız.
Bu programda göstereceğim şey, ana iş parçacığımızın iki iş parçacığı başlatacağıdır,
değil mi?
Bu iki iplik ikinci ve üçüncü iplik olsun.
Doğru.
Yani bunlar, ana iş parçacığının çatallanacağı iki alt iş parçacığı için iki iş parçacığı tanıtıcısıdır.
Şimdi bu programın işlevselliği, ana iş parçacığımız alt iş parçacıkları oluşturduğunda, alt iş parçacıklarının oluşturulması
sırasında, ana iş parçacığımızın bu alt iş parçacıklarına argüman olarak bir tamsayı değeri sağlayacağıdır.
Bu alt iş parçacıkları sadece bu tamsayı değerinin karesini hesaplar ve sonucu ana iş parçacığına döndürür.
Doğru.
Başka bir deyişle, bu iki alt iş parçacığı hiçbir şey yapmaz, ancak yalnızca kendilerine iletilen bir tamsayı girdisinin
karesini hesaplarlar.
Doğru.
Başlangıç olarak, ana iş parçacığımızda yapacağımız ilk şey thread handle kullanarak alt iş parçacıklarından
birini oluşturmaktır.
Değil mi?
Ve ikinci argümanı, bu iş parçacığının karesini hesaplaması gereken değer olarak geçiyoruz.
Doğru.
Bu işlev dizisinin uygulanmasını kısaca tartışacağız.
Alt çizgi oluştur.
Bu kullanıcı tanımlı bir işlevdir ve standart bir Posix işlevi değildir.
Benzer şekilde, ana iş parçacığı p iş parçacığı üç olan başka bir tanıtıcıyı kullanarak başka bir iş parçacığı oluşturacak ve bu iş
parçacığına argüman olarak on tamsayı değerini iletmemize izin verecektir.
Doğru.
Şimdi thread underscore create fonksiyonunun uygulamasını tartışalım.
Gördüğünüz gibi thread underscore create fonksiyonu iki argüman kabul eder.
İlk argüman iş parçacığı tanıtıcısına bir işaretçidir ve ikinci argüman ilettiğimiz tamsayı
değeridir.
Bu tamsayı değerini iş parçacığı kimliği olarak adlandıralım.
Doğru.
Şimdi, bu fonksiyonun sorumluluğu yeni bir iş parçacığı oluşturmaktır.
Şimdi P tipinde bir değişken almamız gerekiyor T Sağ özniteliği.
Bu değişken, oluşturmakta olduğumuz yeni iş parçacığının özelliklerini belirtmek için kullanılır.
Doğru.
Birleştirilebilir bir iş parçacığı oluşturacağımızdan, oluşturacağımız iş parçacığının özelliklerini veya niteliklerini
belirtmek için.
Posix standardı bize iş parçacığı özelliğini sağlar.
Durum olarak ayarlayın.
Bu API özellikle oluşturacağımız iş parçacığının birleştirilebilir bir iş parçacığı mı yoksa ayrılmış bir iş parçacığı mı olduğunu
belirtmek için kullanılır.
Doğru.
Yani bu API'de, sadece öznitelik değişkeninin adresini aktarın ve iş parçacığınızın birleştirilebilir bir iş parçacığı mı yoksa
ayrılmış bir iş parçacığı mı olduğunu belirten bayrağı aktarın.
Doğru.
Posix standardının pthreadcreate joinable olan bu sabit değeri sağladığını varsayalım.
Eğer ayrılmış bir iş parçacığı oluşturmak istiyorsanız, bu durumda pthreadcreate detached değerini belirtmeniz
gerekir.
Doğru.
Dolayısıyla, bu niteliğe ikinci parametre olarak ne geçtiğinize bağlı olarak, oluşturacağınız yeni iş parçacığı birleştirilebilir
veya ayrılabilir olacaktır.
Dolayısıyla bu işlev, bu öznitelik değişkeninde ikinci argüman olarak belirttiğiniz değeri basitçe ayarlar.
Artık bu öznitelik değişkeninin iç tanımı hakkında endişelenmenize gerek yok.
Tek yapmanız gereken bu değişkenin adresini bu fonksiyona ilk argüman olarak aktarmaktır.
Değil mi?
Ve şimdi yeni bir iş parçacığı başlatmak için bir API iş parçacığı, alt çizgi, oluşturma çağırma konumundayız.
Doğru.
Yani 41 numaralı satır bir çatal noktasıdır ve bir iş parçacığı oluşturmamıza izin verin, iş parçacığı oluşturduğunuz iş parçacığı tanıtıcısını
geçirin.
Joinable olarak belirlediğimiz özniteliği geçirin.
Kısa süre içinde belirleyeceğimiz iş parçacığı geri arama işlevini ve argümanı işleve geçirin.
Şimdi fonksiyonun argümanı hiçbir şey değildir, ancak thread create fonksiyonuna ikinci bir argüman olarak aktardığımız
bir tam sayıdır.
Ve size söylediğim gibi, heap bellek deposunu veya statik depolamayı her zaman fonksiyona bir argüman olarak geçirmeliyiz.
Bu nedenle, bu tamsayı girdisini depolamak için bir yığın bellek alacağım.
Değil mi?
Yani burada yerel değişkenin değil, yığın belleğin adresini geçiyorum.
Doğru.
Dolayısıyla 44 numaralı satır bir çatal noktasıdır ve işlev iş parçacığı işlev geri çağrısında yürütmeye başlayacak
bir iş parçacığı oluşturacaktır.
Doğru.
Şimdi bu iş parçacığı geri arama işlevinin uygulanmasını tartışalım.
Dolayısıyla, iş parçacığı işlevi geri çağrısında, söylediğim gibi, alt iş parçacığının yapacağı tek anlamlı
iş, iş parçacığına argüman olarak aktardığımız girdinin karesini hesaplamaktır.
Doğru.
Öyleyse, iş parçacığı geri arama işlevine aktardığımız argümanı çıkaralım.
Değil mi?
Ve şimdi, bu argümanın değerini yerel bir değişkene okuduğumuz için, artık bu argümana kesinlikle
ihtiyaç yoktur.
Bu hafızayı serbest bırakabiliriz, değil mi?
Ve şimdi bu iş parçacığının yürütülmesinde biraz zaman harcamasına izin verelim.
Doğru.
Herhangi bir mantığı takip edebilirsiniz, ancak benim yapacağım şey basitçe bir döngü oluşturacağım
ve bu iş parçacığının işini yaptığını gösteren bir mesaj yazdıracağım ve bir saniyelik
bir uyku yapacağım ve bu iş parçacığının bu işleve argüman olarak aktardığınız tamsayı sayısı kadar döngü içinde çalışmasını
sağlayacağım.
Değil mi?
Yani tüm bu mantık, iş parçacığının işini doğru yapması için sonlu bir süre geçiyormuş
gibi simüle etmek içindir.
Ve işini tamamladıktan sonra, iş parçacığı sonucunu döndürmelidir.
Bu nedenle iş parçacığının sonucu her zaman bir yığın depolama alanında döndürülmelidir.
İşte bu nedenle, tamsayının karesini saklayacağım belleği kilitledim.
Değil mi?
İş parçacığı kimliğinin bu iş parçacığına argüman olarak aktardığımız tam sayı olduğunu hatırlayın ve ben
sadece bu sayının karesini hesaplıyorum ve bu sonuç değişkeninde saklıyorum.
Doğru ve sonuç, yığın depolama alanına bir işaretçidir.
Şimdi bu iş parçacığı işlevi bu yığın depolama alanının adresini döndürmelidir.
Değil mi?
Bunu, iş parçacığı işlevinin dönüş değeri her zaman void star olduğundan, bu depolama işaretçisini bir void
star olarak tipleyerek yapabilir.
Doğru.
Böylece bunun bu fonksiyonun uygulaması olduğunu görebilirsiniz.
Ve bu işlevde, iş parçacığı bazı işler yapıyormuş gibi taklit edecek sınırlı miktarda zaman harcamayı
seçiyoruz.
Ve sonra basitçe tamsayının karesini hesaplarız ve sonuç olarak bu tamsayıyı döndürürüz.
Değil mi?
Şimdi ana fonksiyona geldiğimizde, iki iş parçacığı oluşturduğumuzu görebilirsiniz.
İlk iş parçacığı işini yaparken iki saniye harcarken, ikinci iş parçacığı işini yaparken 10 saniye
harcayacaktır, iki saniye sonra ikinci iş parçacığı sonlanacak ve 10 saniye sonra üçüncü iş parçacığı
sonlanacaktır.
Doğru.
Şimdi bu iki çocuk iş parçacığının ana iş parçacığı olan ana iş parçacığımızın bu iki iş parçacığına katılmasını
nasıl sağlayacağımızı görelim.
Şimdi ana iş parçacığımızın iki numaralı iş parçacığının kendisine katılmasını beklemesini sağlayalım.
Doğru.
Bu basitçe, ana iş parçacığımızın bir API iş parçacığını çağırması gerektiği anlamına gelir, alt çizgi birleştirme.
Doğru ve iş parçacığının tutamacını geçmesi gerekiyor.
İki numara, bu ikinci konu.
Ve şimdi iş parçacığından sonucu toplamak için.
İki numara, P iş parçacığı işlevinin ikinci argümanı alt iş parçacığından döndürülen sonucu toplamak
için kullanılır.
Dolayısıyla, iş parçacığı sonucu iki aslında void star türünde bir değişkendir.
Değil mi?
Ve boş yıldız bellek konumunun adresini aktarmanız gerekir, böylece iki numaralı iş parçacığı
gelip 88 numaralı satırdaki bu birleşme noktasına katıldığında, alt iş parçacığının sonucu
bu beyaz iş parçacığı sonucu tarafından işaret edilecektir.
Doğru.
Yani bu bir işaretçi tipi değişkendir.
Böylece ana iş parçacığı 88 numaralı satıra ulaştığında engellenecektir.
Değil mi?
Bu yüzden bloklamadan önce, ana iş parçacığımızın tam olarak neyi doğru yaptığını bize anlatmak için anlamlı bir mesaj
yazdırmasına izin verin.
Bu yüzden sadece ana iş parçacığımızın p iş parçacığında engellendiğine dair bir mesaj yazdırıyorum.
İkinci konu için API'ye katılın.
Doğru.
Yani ana işlev p iş parçacığında engellendi.
İkinci konu için katılın.
Doğru.
Şimdi ana iş parçacığımız 93 numaralı satırı çalıştıracaktır.
Yalnızca alt iş parçacığı P iş parçacığı iki yürütmeyi tamamladığında ve 91 numaralı satırda ana iş parçacığımıza
katıldığında.
Doğru.
P iş parçacığı katılımı engelleyici bir API'dir ve ana iş parçacığı, alt iş parçacığı p iş parçacığı ana iş parçacığımıza
katılana kadar engellenecektir.
Doğru.
Böylece ana iş parçacığımız p iş parçacığı birleştirme işlevinde engeli kaldıracaktır.
P thread two tarafından döndürülen sonuç bu bellek konumunda mevcut olacaktır.
Doğru.
Şuna bir bakalım.
Bu bellek konumunda ne var?
Her zaman alt iş parçacığının dönüş işaretçisinin null olup olmadığını kontrol edin çünkü bir iş parçacığı null döndürebilir.
Doğru.
Ve eğer null döndürmediyse, bu, bazı anlamlı içeriklere sahip anlamlı bir bellek olduğu anlamına
gelir.
Şimdi iş parçacığı tarafından döndürülen içeriği yazdıralım.
İki.
Yani yaptığım şey, basitçe thread result two değişkenini int star'a dönüştürmek ve değeri
yazdırmak.
Doğru.
Bu, tam sayının karesinin bu belleğe yazıldığı ve benim bu tam sayıyı bu bellekten yazdırdığım
anlamına gelir.
Şimdi, sonucu çıkardıktan sonra, belleği serbest bırakacağım.
Doğru.
Bu iş parçacığı Sonuç iki'nin iş parçacığı geri arama işlevinde dinamik olarak ayrılmış bellek olduğunu unutmayın, bu nedenle
onu doğru şekilde serbest bırakmanız gerekir.
Aksi takdirde bellek sızıntısına neden olursunuz.
Bu nedenle, alt iş parçacığından sonucu topladıktan sonra belleği serbest bırakmayı asla unutmayın.
Değil mi?
Alt iş parçacığı tarafından sonuçları sağlamak için kullanılan belleği serbest bırakmak üst iş parçacığının
sorumluluğundadır.
Doğru.
Ve şimdi basitçe iş parçacığı sonucunu null değişkenine atayabilirsiniz.
Doğru.
Şimdi de benzer bir yaklaşımı üç numaralı konu için yapmamız gerekiyor.
Bu nedenle, üç numaralı iş parçacığı için, kullanıcıya ana iş parçacığının engellendiğini bildirmek için yine bir mesaj yazdıracağım.
Üç numaralı çocuk ipliği için.
Şimdi ana iş parçacığımız p thread join fonksiyonunu tekrar çağıracak, ancak bu sefer bu fonksiyonu sağdaki thread handle
three üzerinde çağıracak ve p thread three tarafından döndürülen sonucu toplamak için voidstart tipi
değişkenin adresini aktaracaktır.
Doğru.
Dolayısıyla, ikinci p iş parçacığı birleştirme işlevini çağırdıktan sonra, ana iş parçacığımız
105 numaralı satırda engellenir.
Üç numaralı iş parçacığının yürütmeyi tamamlayıp geri dönmesi bekleniyor.
Şimdi yine, ana iş parçacığımızın üç numaralı iş parçacığı tarafından sağlanan sonucu toplaması
gerekiyor.
Bu da aynı mantığı izleyeceğimiz ve üç numaralı iş parçacığı tarafından döndürülen tamsayı değerini okumaya
çalışacağımız anlamına gelir.
Doğru.
Böylece demo programımızın uygulaması tamamlanmış oldu.
Yani her şeyin oldukça basit ve anlaşılır olduğunu görebilirsiniz.
Bu demo programda yaptığım şey, ana iş parçacığından iki alt iş parçacığı oluşturmak,
değil mi?
Ve bu iki alt iş parçacığı, bu iş parçacıklarına argüman olarak aktarılan tamsayı değerinin karesini
hesaplar.
Doğru.
Ve bu ana konu.
Önce iki numaralı iş parçacığının katılmasını bekleyin ve iki numaralı iş parçacığı geri gelip ana iş parçacığına katıldığında,
ana iş parçacığı iki numaralı iş parçacığı tarafından sağlanan sonucu toplar.
Doğru.
Bundan sonra ana iş parçacığımız üç numaralı iş parçacığının katılmasını bekler.
Doğru.
Ve üç numaralı iş parçacığı geri gelip ana iş parçacığına katıldığında, ana iş parçacığı sadece üç numaralı
iş parçacığı tarafından sağlanan sonucu toplar.
Doğru.
Yani aynı şey bu diyagramda da gösterilmektedir.
Bir ana iş parçacığımız var.
İki konu başlığı oluşturmuştur.
İki numaralı iplik ve üç numaralı iplik bir birleşme noktası J bir.
Ana iş parçacığımız iş parçacığını bekliyor.
Ana iş parçacığımıza katılmak ve J bağlantı noktasını eklemek için iki numaralı iş parçacığı, üç numaralı iş parçacığının katılmasını
bekliyor.
Doğru.
Şimdi demo programını çalıştıracağım ve beklentim iki numaralı iş parçacığının iki saniye
boyunca çalışması.
Ve sonlandırıldığında, ana iş parçacığına dört değerini döndürmelidir.
Doğru.
Ve üç numaralı iplik 10 saniye boyunca çalışmalıdır.
Ve sonlandırıldıktan sonra ana iş parçacığına 100 değerini döndürmelidir.
Doğru.
Programı çalıştırdığımda, iki numaralı iş parçacığımızın iki saniye boyunca çalıştığını ve ardından sonucu ana iş parçacığına
döndürdüğünü görebilirsiniz.
Doğru.
Programı çalıştırdığınızda, ana fonksiyonun veya ana iş parçacığının ilk p iş parçacığında bloke olduğunu
görebilirsiniz.
Aramaya katıl.
Doğru.
Yani, iki numaralı iş parçacığının katılmasını bekliyor.
İki numaralı iş parçacığı iki saniye boyunca işini yaptıktan sonra sonlandırılır ve ana iş parçacığına katılmak
üzere ana iş parçacığına geri döner.
Doğru.
Ana iş parçacığı ve iki numaralı iş parçacığı ana iş parçacığına katıldığında, ana iş parçacığı iki numaralı
iş parçacığının sonucunu toplar ve sadece iki numaralı iş parçacığı tarafından döndürülen sonucu yazdırır.
Doğru.
Şimdi burada ana iş parçacığının ilk p iş parçacığından engellenmediğini görebilirsiniz.
Ana iş parçacığına katılın, ardından ilk birleşme noktasının ötesinde yürütmeye devam edin ve ardından ikinci birleşme
noktasında engellenir.
Doğru.
Ve üç numaralı iş parçacığı birkaç saniye daha çalışırken, üç numaralı iş parçacığı geri gelip ana iş parçacığına
katıldığında, ana iş parçacığı üç numaralı iş parçacığının sonucunu toplar ve doğru şekilde
yazdırır.
Ve bundan sonra ana iş parçacığımız da sonlanır.
Şimdi bu programda, size bir soru sorarsam, iki numaralı P iş parçacığı 10 saniye boyunca çalıştırılsaydı
ve ardından üç numaralı P iş parçacığı iki saniye boyunca çalıştırılsaydı senaryo ne olurdu, değil mi?
Bu yüzden sizden bu değerleri değiştirmenizi ve alt iş parçacıklarını farklı zaman aralıklarında beklettiğinizde programınızın
nasıl davrandığını gözlemleyerek anlamaya çalışmanızı rica ediyorum.
Doğru.