Varsayılan olarak, C programlarında eşzamanlılık veya paralellik yoktur, bir seferde yalnızca bir görev gerçekleşir, her kod satırı sırayla okunur. Ancak bazen bir dosyayı okumanız gerekir veya – Daha da kötüsü – Uzak bir bilgisayara bağlı bir soket ve bir bilgisayar için çok uzun zaman alıyor. Genellikle 1 saniyeden az sürer, ancak 1 CPU çekirdeği uygulamak için 1 veya 2 milyar Bu süre zarfında talimatlar.
Onun gibi, İyi bir geliştirici olarak, beklerken daha yararlı bir şey yapmak için C programınızı sipariş etmek isteyeceksiniz. Eşzamanlı programlamanın imdadınıza yetiştiği yer burasıdır – Ve daha çok çalışması gerektiğinden bilgisayarınızı perişan eder.
Burada size eş zamanlı programlama yapmanın en güvenli yollarından biri olan Linux fork sistem çağrısını göstereceğim.
Evet o yapabilir. Örneğin, arama yapmanın başka bir yolu var. Çok yönlü. Daha hafif, ama olabilir tamamen Yanlış kullanırsan yanlış olur. Programınız yanlışlıkla bir değişken okur ve
aynı değişken Aynı zamanda programınız tutarsız ve neredeyse algılanamaz hale gelecektir – Geliştiricinin en kötü kabusu.
Aşağıda göreceğiniz gibi çatal hafızayı kopyalar, bu nedenle değişkenlerle ilgili bu tür problemler mümkün değildir. Ayrıca çatal, her eşzamanlı görev için bağımsız bir eylem gerçekleştirir. Bu güvenlik önlemleri nedeniyle, çatal kullanarak yeni bir eşzamanlı görev başlatmak, çoklu okumadan yaklaşık 5 kat daha yavaştır. Gördüğünüz gibi, sağladığı pek çok fayda yok.
Şimdi bu kadar açıklama, ilk C programınızı fork call ile test etme zamanı.
Linux çatalı örneği
İşte kod:
#birleştirmek için
#birleştirmek için
#birleştirmek için
#birleştirmek için
#birleştirmek için
int o(){
pid_t çatalı;
çatal = çatal();
/* Bebek… */
eğer(çatal ==0){
Baskı(Oğlan koşuyor, koşuyor.\n“);
uyumak(5);
Baskı(Çocuğun işi bitti, gidiyor.\n“);
/* ebeveynler… */
}diğereğer(çatal ! =–1){
Baskı(“Babam bekliyor…\n“);
Bekle(boş);
Baskı(“Babam gidiyor…\n“);
}diğer{
a kadar(“Çatal işlevi çağrılırken hata oluştu”);
}
dönüş0;
}
Sizi yukarıdaki kodu test etmeye, derlemeye ve çalıştırmaya davet ediyorum, ancak çıktının nasıl görüneceğini görmek istiyorsanız ve onu derlemek için fazla “tembelseniz” – Sonuçta, bütün gün C programlarını derleyen yorgun bir geliştirici olabilirsiniz. C programınızın çıktısını ve onu derlemek için kullandığım komutu aşağıda bulabilirsiniz:
$ GCC ülkeleri –Temel=C89 –bilgiçlik –Duvar çatalıc–o çatal –O2
$./çatal
Anne babalar bekliyor…
Bebek bir işVe işleme yapılır.
Bebek tamamlandıVe Dışarı.
ebeveynler ortaya çıkıyor…
Çıktı yukarıdaki çıktıyla %100 aynı değilse lütfen paniğe kapılmayın. Görevleri aynı anda çalıştırmanın, görevlerin sıra dışı olduğu ve önceden belirlenmiş bir sıra olmadığı anlamına geldiğini unutmayın. Bu örnekte, koşan çocuğu görebilirsiniz. önce – ondan önce ebeveyn bekliyor Bunda bir yanlışlık yok. Genel olarak sıralama, çekirdek sürümüne, CPU çekirdeği sayısına, bilgisayarınızda çalışan yazılıma vb. bağlıdır. Duruma göre değişir.
Tamam, şimdi koda geri dön. fork() satırından önce, bu C programı tamamen normaldir: her seferinde bir satır, bu program için yalnızca bir işlem yürütür (fork’tan önce küçük bir gecikme varsa, bunu görev yöneticinizden onaylayabilirsiniz).
Fork()’tan sonra paralel olarak çalışabilen iki process vardır. İlk olarak, bir alt süreç var. Bu işlem çatal () üzerinde oluşturulur. Bu alt süreç özeldir: fork() kullanan satırın üzerindeki hiçbir kod satırını çalıştırmamıştır. Ana işlevi çağırmak yerine fork() satırını çalıştıracaktır.
Çataldan önce bildirilen değişkenler ne olacak?
Pekala, Linux fork() ilginç çünkü soruyu zekice yanıtlıyor. Değişkenler ve aslında C programlarındaki tüm bellek alt sürece kopyalanır.
Fork’un ne yaptığını birkaç kelimeyle açıklayayım: klonlama adlandırma işlemi İki işlem hemen hemen aynı: tüm değişkenler aynı değerlere sahip olacak ve her iki işlem de fork()’tan hemen sonra satırı yürütecek. Ama klonlamadan sonra, Ayrıldılar. Bir süreçte bir değişkeni güncellerseniz, diğer süreç genellikle Değişkeni güncelleyin. Onlar gerçekten klonlar, kopyalar, neredeyse hiçbir ortak noktası olmayan süreçlerdir. Gerçekten yararlıdır: bir veri dizisi hazırlayabilir ve ardından fork()’u hazırlayabilir ve bu verileri tüm durumlarda kullanabilirsiniz.
Tahsis, fork() bir değer döndürdüğünde başlar. Orijinal süreç (bu ana süreç) klonlanan işlemin işlem kimliğini alır. Öte yandan, klonlama işlemi (bu alt süreç) 0 sayısını alacaktır. Şimdi if / else if ifadelerinin neden fork() satırından sonra yerleştirildiğini anlamaya başlamalısınız. Dönen değerle, çocuktan ebeveynin yaptığından farklı bir şey yapmasını isteyebilirsiniz – Ve inan bana, faydalı.
Bir yandan yukarıdaki kod örneğinde çocuk 5 saniye süren bir görevi gerçekleştiriyor ve bir mesaj yazdırıyor. Uzun süren bir işlemi simüle etmek için uyku işlevini kullanıyorum. Sonra çocuk başarıyla çıkar.
Öte yandan, ebeveyn bir mesaj yazdırır, çocuğun çıkmasını bekler ve son olarak başka bir mesaj yazdırır. Bir ebeveynin çocuğunu beklemesi önemlidir. Örneğin, ebeveyn bu sürenin çoğunu çocuğunu beklemek için bekler. Ancak, beklemelerini söylemeden önce ebeveyne uzun süren herhangi bir görevi yapmasını söyleyebilirim. Böyle beklemek yerine faydalı bir iş çıkarırdı. Sonuçta, biz buna alışkınız çatal (), hayır?
Ancak yukarıda da söylediğim gibi asıl önemli olan Ebeveynler çocuklarını bekliyor. bu önemli çünkü zombi operasyonları.
beklemek ne kadar önemli
Ebeveynler genellikle çocuklarının işlemlerini tamamlayıp tamamlamadığını bilmek isterler. Örneğin, görevleri paralel olarak yürütmek istiyorsunuz, ancak kesinlikle istemezsin böylece çocuklar ebeveynleri bitirmeden önce çıkar, çünkü bu olursa, kabuk çocuklar bitirmeden önce bir bilgi istemi döndürür – hangisi garip.
Wait işlevi, bir alt işlemin sona ermesini beklemenizi sağlar. Bir ebeveyn fork()’u 10 kez çağırırsa, ayrıca wait()’i de 10 kez çağırması gerekir, Her çocuk için bir kez oluşturuldu.
Peki ya ebeveyn, tüm çocuklar buna sahipken bekleme işlevini çağırırsa? Önceden Çıktı mı Burası zombi operasyonlarına ihtiyaç duyulan yer.
Ebeveyn wait() işlevini çağırmadan önce çocuk çıkarsa, Linux çekirdeği çocuğun çıkmasına izin verir. Ama bir bilet tutacak Çocuğa dışarıda olduğunuzu söyleyin. Ardından ebeveyn wait() işlevini çağırdığında bileti bulur, bileti siler ve wait() işlevi geri döner. Şu anda Çünkü ebeveynin çocuğun işi bittiğinde bilmesi gerektiğini bilir. Bu biletin adı zombi operasyonu.
Bu nedenle ebeveynin wait() işlevini çağırması önemlidir: aramazsa zombi işlemleri bellekte ve Linux çekirdeğinde kalır. onu yapamam Birkaç zombi sürecini bellekte tutun. Sınıra ulaşıldığında, bilgisayarınızYeni süreçler oluşturulamıyor Ve böylece bir çok kötü form: a kadar Bir süreci öldürmek için onun için yeni bir süreç oluşturmanız gerekebilir. Örneğin, bir işlemi sonlandırmak için görev yöneticinizi açmak isterseniz, açamazsınız çünkü görev yöneticinizin yeni bir işleme ihtiyacı olacaktır. Daha da kötüsü Yapamazsın Zombi sürecini öldür.
Bu nedenle beklemeyi çağırmak önemlidir: çekirdeğe izin verir. temizlik Sonlandırılmış süreçlerin bir listesini derlemek yerine çalışan süreç. Peki ya ebeveyn görüşmeyi hiç bırakmadıysa? Bekle()?
Neyse ki, ebeveyn sonlandırıldığı için, başka hiç kimse bu çocuklar için wait()’i çağıramaz, yani sebepsiz Bu zombi operasyonlarını sürdürmek için. Bu nedenle, bir ebeveyn ayrıldığında, Tüm kalan zombi operasyonları Bu ebeveyne bağlıdır Kaldırma. zombi operasyonları tamamen Ebeveyn işlemlerinin yalnızca çocuğun, ebeveyn wait() adlı ebeveynden önce bitirdiğini bulmasına izin vermek için kullanışlıdır.
Artık herhangi bir sorun yaşamadan çatalınızdan en iyi şekilde yararlanabilmeniz için bazı güvenlik önlemlerini öğrenmeyi tercih edebilirsiniz.
Çatalın amaçlandığı gibi çalışması için basit kurallar
İlk olarak, çoklu iş parçacığına alışkınsanız, lütfen iş parçacıklı bir programı çatallamayın. Aslında, genel olarak birkaç eşzamanlılık teknolojisini karıştırmaktan kaçının. çatal, normal C programlarında çalıştığını varsayar, yalnızca paralel bir görevi klonlamak içindir, başka bir şey değil.
İkinci olarak, fork()’tan önce dosyaları açmaktan veya açmaktan kaçının. Dosyalar tek şeylerden biridir abone ne de çoğaltılmış ebeveyn ve çocuk arasında. Başlangıçta 16 bayt okursanız, okuma işaretçisini 16 bayt ileri taşır İkisi birden ebeveynde ve çocukta. en kötüeğer çocuk ve ebeveyn bayt yazarsa aynı dosya Orijinal baytlar da olabilir karışık Bir bebek baytı ile!
Açık olmak gerekirse, STDIN, STDOUT ve STDERR dışında açık dosyaları klonlarla gerçekten paylaşmak istemezsiniz.
Üçüncüsü, soketlere dikkat edin. prizler sende paylaş ebeveynler ve çocuklar arasında. Bir bağlantı noktasını dinlemek ve ardından yeni bir istemci bağlantısını yönetmeye hazır birden çok astınız olması yararlıdır. ikinciYanlış kullanırsan başın belaya girer.
Dördüncüsü, fork()’u bir döngü içinde çağırmak istiyorsanız, bunu şununla yapın: Nihai bakım. Bu kodu alalım:
/* bunu derle */
Sabit miktarint Hedef =4;
pid_t çatalSonucu
için(int Kahve =0; Kahve < Hedef; Kahve++){
çatal sonuç = çatal();
/* … */
}
Kodu okursanız, 4 çocuğun doğmasını bekleyebilirsiniz. Ama daha fazlasını yaratacak 16 çocuk. Çünkü çocuklar yapacak Dahası Döngüyü yürütün, böylece çocuklar ayrıca fork()’u çağırır. Döngü sonsuz olduğunda çağrılır. dikenli bomba Linux’u yavaşlatmanın yollarından biridir. O kadar ki artık çalışmıyor Yeniden başlatma gerekli olacaktır. Kısacası, Klon Savaşlarının sadece Star Wars’ta tehlikeli olmadığını unutmayın!
Artık basit bir döngünün nasıl hata alabileceğini gördünüz, döngüler fork() ile nasıl kullanılır? Bir for döngüsüne ihtiyacınız varsa, her zaman çatalın dönüş değerini kontrol edin:
Sabit miktarint Hedef =4;
pid_t çatalSonucu;
int Kahve =0;
yapmak{
çatal sonuç = çatal();
/* … */
Kahve++;
}Süre((çatal sonuç ! =0&& çatal sonuç ! =–1)&&(Kahve < Hedef));
çözüm
Şimdi fork() ile kendi deneylerinizi yapma zamanı! Görevleri birden çok CPU çekirdeğinde çalıştırarak zamanı iyileştirmenin yeni yollarını deneyin veya bir dosyanın okunmasını beklerken arka planda biraz işlem yapın!
Erkek erkeğe sayfaları okumaktan çekinmeyin. İşte fork() tam olarak nasıl çalışır, hangi hataları alabilirsiniz, vb. öğreneceksiniz. Ve senkronizasyonun tadını çıkarın!
Diğer gönderilerimize göz at
[wpcin-random-posts]
İlk Yorumu Siz Yapın