Sinyal göz ardı edilebilir mi (kaybolabilir)?


9

İşçilerle sinyaller aracılığıyla iletişim kuran bir uygulamam var (partiküller SIGUSR1 / SIGUSR2 / SIGSTOP).

Ne olursa olsun her sinyalin işleyici tarafından teslim edilip işleneceğine güvenebilir miyim?

Sinyaller, uygulamanın bunları işlemesi için mümkün olmadığından daha hızlı gönderilirse ne olur (örneğin, şu anda yüksek ana bilgisayar yükü nedeniyle)?

Yanıtlar:


8

"Çok fazla sinyal" probleminin yanı sıra, sinyaller açıkça göz ardı edilebilir. Gönderen man 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

Sinyaller de engellenebilir. Gönderen man 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

Hem engellenen hem de yoksayılan sinyal setleri alt süreçler tarafından miras alınır, bu nedenle uygulamanızın üst süreci bu sinyallerden birini yok saydı veya engelledi olabilir.

İşlem öncekileri işlemeyi bitirmeden önce birden fazla sinyal iletildiğinde ne olur? Bu işletim sistemine bağlıdır. signal(2)Tartışıyor bunu Yukarıda bağlı manpage:

  • Sistem V, sinyal düzenini varsayılana sıfırlar. Daha da kötüsü, birden fazla sinyalin hızlı iletimi, yinelemeli (?) Çağrılara neden olur.
  • BSD, işleyici bitene kadar sinyali otomatik olarak engeller.
  • Linux'ta bu, GNU için ayarlanan derleme bayraklarına bağlıdır libc, ancak BSD davranışını beklerim.

4
Linux'un man sayfası, bunun yerine signal(2)bu karışıklığı önlediğinizi vurgulamaktadır sigaction(2).
Nate Eldredge

7

Gönderilen her sinyalin teslim edileceğine güvenemezsiniz. Örneğin, bir işlem, SIGCHLD'yi çıkmış bir alt işlemden alırken uzun zaman alıyorsa , linux çekirdeği SIGCHLD'yi "birleştirir" .

Sorunuzun başka bir bölümünü yanıtlamak için, bir dizi farklı sinyal aralığın çok kısa sürede geliyorsa sinyaller çekirdeğin içinde "kuyruğa alınır".

Sen kullanmalıdır sigaction()ile sinyal işleyicisi kurmak sa_sigactionüyesi siginfo_tayarlayarak, sa_masküyesi siginfo_tdikkatlice argüman. Bunun en azından tüm "asinkch" sinyallerini maskelemek anlamına geldiğini düşünüyorum. Linux için man sayfasına göre sigaction(), işlenen sinyali de maskeleyeceksiniz. sa_flagsÜyeyi SA_SIGINFO olarak ayarlamanız gerektiğini düşünüyorum , ama neden bu batıl inancım olduğunu hatırlayamıyorum. Bunun, işleminize hiçbir yarış koşulu olmadan ayarlanmış bir sinyal işleyici ve diğer çoğu sinyal tarafından kesintiye uğramayan bir sinyal işleyici alacağına inanıyorum.

Sinyal işleyici fonksiyonunuzu çok, çok dikkatli bir şekilde yazın. Temel olarak, bir sinyalin yakalandığını belirtmek için küresel bir değişken ayarlayın ve sürecin geri kalanı bu sinyal için istenen eylemle ilgilensin. Sinyaller bu şekilde en az bir süre maskelenecektir.

Ayrıca, sinyal işleme kodunuzu çok ayrıntılı bir şekilde test etmek isteyeceksiniz. Küçük bir test sürecine koyun ve 2 veya 3 özel amaçlı sinyal gönderme programından mümkün olduğunca çok sayıda SIGUSR1 ve SIGUSR2 sinyali gönderin. Kodunuzun SIGUSR1 ve SIGUSR2'yi hızlı ve doğru bir şekilde işleyebileceğinden emin olduktan sonra diğer bazı sinyalleri de karıştırın. Kendinizi zor hata ayıklamaya hazırlayın.

Eğer linux ve sadece linux kullanıyorsanız signalfd(), select()bu sinyalleri almak için yapabileceğiniz veya yoklayabileceğiniz bir dosya tanımlayıcı oluşturmak için kullanmayı düşünebilirsiniz . Kullanımı signalfd()hata ayıklamayı kolaylaştırabilir.


2
Birleştirilen sadece SIGCLD değil: tüm sinyaller işlenmeden önce teslim edilirlerse potansiyel olarak birleştirilir.
Gilles 'SO- kötü olmayı bırak

SIGCHLD sinyalleri için "ne kadar" uzunluğunun ölçüsü var mı? Programımda şu anda bu davranışı yaşıyorum ve sinyal işleyicim ~ 100 ms'den fazla sürmüyor sanırım.
xrisk

@Rishav - bildiğim kadarıyla "çok uzun" ne olduğunu öğrenmenin bir yolu yok. Genel sistem yükünün önemli olmasını beklerim. Yani, diğer işlemlerin ve çekirdeğin yaptığı şey, birleşmeleri için sinyaller arasındaki "ne kadar süreceğini" etkileyecektir. Yararlı bir cevap değil, sanırım.
Bruce Ediger

6

Bir işlem başarılı bir şekilde çağırırsa, bir sinyalin iletilmesi garanti edilir. kill, daha sonra hedef sinyali alır. Bu zaman uyumsuzdur: Gönderenin sinyalin ne zaman alındığını veya işlendiğini bilmesinin bir yolu yoktur. Ancak bu, sinyalin iletileceğini garanti etmez. Hedef, sinyali işlemeden önce ölebilir. Hedef, iletildiği sırada sinyali görmezden geliyorsa, sinyalin bir etkisi olmayacaktır. Hedef, işlenmeden önce aynı sinyal numarasının birden çok örneğini alırsa, sinyaller birleştirilebilir (ve genellikle birleştirilebilir): aynı sinyali bir işleme iki kez gönderirseniz, işlemin sinyali alıp almayacağını bilemezsiniz bir veya iki kere. Sinyaller çoğunlukla bir süreci öldürmek için veya bir süreci dikkat ettirmenin bir yolu olarak tasarlanmıştır, bu şekilde iletişim için tasarlanmamıştır.

Güvenilir teslimat gerekiyorsa, farklı bir iletişim mekanizmasına ihtiyacınız vardır. İşlemler arasında iki ana iletişim mekanizması vardır: bir boru tek yönlü iletişime izin verir; bir soket , aynı sunucuya çift yönlü iletişime ve çoklu bağlantılara izin verir. Gönderdiğiniz sayıda bildirimi işlemek için hedefe ihtiyacınız varsa, bir kanal üzerinden bayt gönderin.


4
Sinyalin iletilmemesinin bazı yollarını anlatmaya devam ettiğiniz için "Bir sinyalin iletilmesi garanti edilir" yazmak mı demek istediniz (yani süreç alınmadan önce öldü veya sinyaller birleştirildi)?
Johnny

2

Çekirdek, bloke edilirken birden fazla teslim edilirse standart sinyalleri birleştirmekte serbesttir. Diğer yandan, gerçek zamanlı sinyaller de benzer şekilde özürlü değildir.

Gönderen sinyal (7) kılavuz sayfasına :

Gerçek zamanlı sinyaller aşağıdakilerle ayırt edilir:

  1. Birden çok gerçek zamanlı sinyal örneği sıraya alınabilir. Buna karşılık, o sinyal şu ​​anda bloke edilmişken standart bir sinyalin birden fazla örneği verilirse, yalnızca bir örnek kuyruğa alınır.

SIGRTMIN - SIGRTMAX aralığında bir sayıya sahip bir sinyal kullanmayı deneyin.


Gerçek zamanlı sinyaller için bir sınır vardır, ancak oldukça yüksektir. Kullanıcı tarafından gönderilen bekleyen bekleyen sinyallerin sayısı RLIMIT_SIGPENDING'i aşarsa bir sinyal bırakılır. ulimit -ibu değeri Ubuntu 18.04'te 63432 olarak gösterir.
bain
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.