wait fork ve disable fork
Gün 4: Süreçler Arası İletişim (IPC) | Süreç bekleme, iptal etme ve timeout kalıbı
Bu derste paralel süreçleri yönetmenin iki temel aracını öğreneceksiniz: wait fork ile arka planda koşan tüm alt süreçlerin bitmesini beklemek ve disable fork ile bunları zorla sonlandırmak. Bu ikisini birleştirerek doğrulamada çok sık kullanılan timeout (zaman aşımı) kalıbını da kuracaksınız.
wait fork ve disable fork
Önceki derste join_none ile başlattığımız süreçlerin arka planda çalışmaya devam ettiğini görmüştük. Peki bu süreçleri sonradan nasıl kontrol ederiz? İşte bu noktada iki anahtar yapı devreye girer:
wait fork→ Çağrıldığı süreç, o ana kadar başlatılmış tüm alt süreçler (forklanmış process'ler) bitene kadar bekler.join_noneile başlatılıp daha sonra "hepsi tamamlandı mı?" kontrolü yapmak istediğinizde idealdir.disable fork→ Çağrıldığı sürecin başlattığı tüm aktif alt süreçleri anında iptal eder (öldürür).join_anysonrası "biri bitti, gerisini umursamıyorum" senaryolarında kullanılır.
Timeout (Zaman Aşımı) Kalıbı
Doğrulamada en kritik kalıplardan biri budur: Bir işin ya başarıyla tamamlanmasını ya da belirli bir süre içinde bitmemesi durumunda hata vermesini istersiniz. Bunun için:
forkiçine iki dal koyarsınız: biri asıl işi yapan görev, diğeri sadece bir gecikme (#timeout) bekleyen bir bekçi (watchdog).join_anyile hangisi önce biterse ana süreç devam eder.disableile geriye kalan (yavaş olan ya da bekçi olan) dal iptal edilir.
Bu kalıp, simülasyonların sonsuza kadar takılıp kalmasını (hang) engeller ve hatalı tasarımları erken yakalar. Adlandırılmış bloklar (fork : timeout_block) sayesinde disable timeout_block ile yalnızca o bloğu hedefli biçimde sonlandırabilirsiniz.
Kaynak Kod
// =============================================================================
// GUN 4 - Konu 2: wait fork ve disable fork
// =============================================================================
module wait_disable_fork;
task automatic slow_task(string name, int delay);
$display(" [%0t] %s basladi", $time, name);
#delay;
$display(" [%0t] %s bitti", $time, name);
endtask
// --- wait fork: Tum cocuk sureclerin bitmesini bekle ---
initial begin
$display("=== wait fork ve disable fork ===\n");
$display("--- wait fork ---");
$display(" [%0t] Ana surec basladi", $time);
fork
slow_task("Task_A", 20);
slow_task("Task_B", 40);
join_none
$display(" [%0t] join_none sonrasi, diger is yapiliyor...", $time);
#10;
$display(" [%0t] Ek is bitti, simdi fork'lari bekliyoruz", $time);
wait fork; // Task_A ve Task_B bitene kadar bekle
$display(" [%0t] wait fork: Tum gorevler tamamlandi!\n", $time);
end
// --- disable fork: Tum cocuk surecleri sonlandir ---
initial begin
#100;
$display("--- disable fork ---");
$display(" [%0t] Baslangic", $time);
fork
begin
slow_task("Uzun_Task", 100); // Cok uzun
end
begin
slow_task("Kisa_Task", 10);
end
join_any
$display(" [%0t] join_any: Biri bitti, digerini iptal ediyoruz", $time);
disable fork; // Kalan surecleri sonlandir
$display(" [%0t] disable fork: Tum bekleyen gorevler iptal edildi\n", $time);
end
// --- Zaman asimi (Timeout) kalibi ---
initial begin
#300;
$display("--- Timeout Kalibi ---");
$display(" [%0t] Baslangic", $time);
fork : timeout_block
begin
slow_task("Hedef_Task", 50);
$display(" [%0t] Hedef gorev basarili!", $time);
end
begin
#30; // 30ns timeout
$display(" [%0t] ZAMAN ASIMI! 30ns icinde bitmedi", $time);
end
join_any
disable timeout_block;
$display(" [%0t] Timeout blogu tamamlandi\n", $time);
#10;
$display("=== wait/disable fork Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
- Birinci
initialbloğu (wait fork):Task_A(20ns) veTask_B(40ns)join_noneile başlatılır, böylece ana süreç beklemeden devam eder. Ana süreç önce#10kadar başka bir iş yapar, ardındanwait fork;ile her iki görevin de bitmesini bekler. En uzun görevTask_B40ns sürdüğü için bekleme bu noktada tamamlanır. - İkinci
initialbloğu (disable fork): Bu blok#100zamanında başlar.Uzun_Task(100ns) veKisa_Task(10ns) paralel başlatılır.join_anysayesinde ilk bitenKisa_Taskana süreci serbest bırakır. Hemen ardından çağrılandisable fork;, hâlâ koşmakta olanUzun_Task'i zorla sonlandırır; bu yüzden onun "bitti" mesajını hiç görmeyiz. - Üçüncü
initialbloğu (Timeout kalıbı):#300zamanında çalışır ve adlandırılmış bir blok olantimeout_blockkullanır. İçindeHedef_Task(50ns) ile 30ns'lik bir bekçi dalı yarışır. Bekçi 30ns < 50ns olduğu için önce biter;join_anyana süreci serbest bırakır ve "ZAMAN AŞIMI!" mesajı yazılır. Ardındandisable timeout_block;ile hâlâ koşanHedef_Taskiptal edilir.
Önemli Noktalar
wait fork, çağrıldığı süreç tarafından başlatılmış alt süreçleri bekler; başka bloklardaki süreçleri kapsamaz. Bu kapsam farkına dikkat edin.disable forketki alanı geniştir ve mevcut süreçteki tüm alt forkları öldürür. Sadece belirli bir bloğu sonlandırmak için adlandırılmış blok (fork : isim) tanımlayıpdisable isim;kullanın.- Timeout kalıbında
join_anysonrasıdisableçağrısını unutmayın; aksi halde yavaş görev arka planda çalışmaya devam edebilir. disableile sonlandırılan bir görev, gecikmesinin (#delay) ortasında "öldürülür"; bu yüzden bitiş mesajları çalışmaz. Kaynak temizliği gerektiren durumlarda bu davranışı göz önünde bulundurun.- Bu üç blok farklı
#gecikmeleriyle (10/100/300) başladığı için birbirine karışmadan, çıktıda sırayla görüntülenir; bağımsız senaryoları aynı modülde göstermenin temiz bir yoludur.