POSIX konuları ve sinyalleri


81

POSIX iş parçacığı ve POSIX sinyallerinin nasıl etkileşim kurduğunun karmaşıklığını anlamaya çalışıyorum. Özellikle şu konularla ilgileniyorum:

  • Bir sinyalin hangi iş parçacığına iletileceğini kontrol etmenin en iyi yolu nedir (ilk etapta ölümcül olmadığını varsayarsak)?
  • Başka bir iş parçacığına (aslında meşgul olabilir) sinyalin geldiğini söylemenin en iyi yolu nedir? (Bir sinyal işleyiciden pthread koşul değişkenlerini kullanmanın kötü bir fikir olduğunu zaten biliyorum.)
  • Başka iş parçacıklarına bir sinyalin oluştuğu bilgisini güvenli bir şekilde nasıl aktarabilirim? Bunun sinyal işleyicide olması gerekiyor mu? (Genel olarak diğer konuları öldürmek istemiyorum; çok daha incelikli bir yaklaşıma ihtiyacım var.)

Bunu neden istediğimle ilgili referans için, TclX paketini iş parçacıkları destekleyecek şekilde nasıl dönüştüreceğimi veya onu nasıl böleceğimi ve en azından bazı yararlı parçaların destek parçalarını nasıl yapacağını araştırıyorum . Sinyaller, özellikle ilgi çekici olan parçalardan biridir.

Yanıtlar:


48
  • Bir sinyalin hangi ipliğe iletileceğini kontrol etmenin en iyi yolu nedir?

@ Zoli2k'in belirttiği gibi, işlenmesini istediğiniz tüm sinyalleri (veya her biri belirli sinyal sorumlulukları olan bir dizi iş parçacığını) işlemek için açıkça tek bir iş parçacığı atamak iyi bir tekniktir.

  • Başka bir iş parçacığına (aslında meşgul olabilir) sinyalin geldiğini söylemenin en iyi yolu nedir? [...]
  • Başka iş parçacıklarına bir sinyalin oluştuğu bilgisini güvenli bir şekilde nasıl aktarabilirim? Bunun sinyal işleyicide olması gerekiyor mu?

"En iyisi" demeyeceğim ama işte tavsiyem:

mainTüm iş parçacıkları bu sinyal maskesini devralacak şekilde içinde istenen tüm sinyalleri engelleyin . Daha sonra, özel sinyal alıcı iş parçacığını, yeni gelen sinyalleri diğer bazı iş parçacığı içi iletişim olarak göndererek, sinyal güdümlü bir olay döngüsü olarak şekillendirin .

Bunu yapmanın en basit yolu, iş parçacığının sigwaitinfoveyasigtimedwait kullanarak bir döngüdeki sinyalleri kabul etmesini sağlamaktır . İş parçacığı daha sonra sinyalleri bir şekilde dönüştürür, belki de a yayınlar pthread_cond_t, diğer iş parçacıklarını daha fazla G / Ç ile uyandırır, uygulamaya özgü iş parçacığı güvenli bir kuyrukta bir komutu sıralar.

Alternatif olarak, özel iplik, sinyallerin bir sinyal işleyiciye iletilmesine izin vererek, yalnızca sinyalleri işlemeye hazır olduğunda teslim için maskeyi kaldırabilir. ( sigwaitİşleyiciler aracılığıyla sinyal iletimi, aile aracılığıyla sinyal kabulünden daha hataya meyillidir .) Bu durumda, alıcının sinyal işleyicisi bazı basit ve eşzamansız sinyal güvenli eylemler gerçekleştirir: sig_atomic_tbayrakları ayarlama , arama sigaddset(&signals_i_have_seen_recently, latest_sig), write() bir bayt tıkanmayan bir kendi kendine boruya vs.

( GÜNCEL haklı @caf işaret sigwaityaklaşımlar üstündür.)


1
Bu, özellikle ölümcül olmayan sinyal işleme için de kullanılabileceği için çok daha yararlı bir cevap. Teşekkürler!
Donal Fellows

1
Sinyal işleme iş parçacığı sinyal işleyicileri hiç kurmazsa en kolayıdır - bunun yerine sigwaitinfo()(veya sigtimedwait()) etrafında döner ve son paragrafta açıklandığı gibi bunları uygulamanın geri kalanına gönderir.
caf

@caf, gerçekten de öyle. Güncellenmiş
pilcrow

14

POSIX standardına göre, tüm iş parçacıkları sistemde aynı PID ile görünmelidir ve kullanarak pthread_sigmask()her iş parçacığı için sinyal engelleme maskesini tanımlayabilirsiniz.

PID başına yalnızca bir sinyal işleyici tanımlanmasına izin verildiğinden, tüm sinyalleri bir iş parçacığında işlemeyi ve pthread_cancel()çalışan bir iş parçacığının iptal edilmesi gerekiyorsa göndermeyi tercih ederim . İş pthread_kill()parçacıkları için temizleme işlevlerini tanımlamaya izin verdiği için tercih edilen yoldur .

Bazı eski sistemlerde, uygun çekirdek desteğinin olmaması nedeniyle, çalışan evreler, ana evrenin PID'sinden farklı PID'ye sahip olabilir. Linux 2.4'te linuxThreads ile sinyal işleme için SSS'ye bakın .


"Uygulandı" dediğinizde ne anlama geliyor? Ayrıca, bir sinyale yanıt olarak diğer evreleri atomize etmek her zaman doğru değildir (SIGHUP ve SIGWINCH daha fazla incelik gerektirir) ve yine de diğer iş parçacıklarını bildirmek için koşul değişkenlerini kullanmak güvenli değildir. Kötü cevap.
Donal Fellows

1
Olumsuz oyumu kaldırdım, ancak yine de yeterli bir cevap değil çünkü bir sinyale yanıt olarak konuları öylece öldüremem. Bazı durumlarda yanıt olarak olayları yerel olarak sıraya koyacağım, diğerlerinde çok dikkatli bir şekilde iş parçacığı parçalamam gerekiyor (BTW, bu parçaları zaten yapmak için makinelerin çoğuna sahibim; işletim sistemi bağlantıları. eksik sinyaller).
Donal Fellows

1
@ zoli2k: Kısa bir süre önce uClibc'nin make menuconfigyeni klonlanmış git ana dalıyla çalıştırmayı denedim . Orada ise 2012 hala NPTL seçme karşı önerir yıl itibariyle eski LinuxThreads ve POSIX iplik uygulamaları gibi yeni NPTL ama yardım arasında bir seçim. Bu nedenle, sistem yeterince güncel Linux çekirdeği çalıştırsa bile, modern gömülü Linux sistemlerinde eski LinuxThreads uygulamasının kullanıldığını görmek hala yaygındır.
FooF

3

Şimdiye kadar neredeyim:

  • Sinyaller farklı ana sınıflarda gelir, bunlardan bazıları genellikle süreci öldürür (SIGILL) ve bazıları hiçbir zaman hiçbir şey yapmaya ihtiyaç duymaz (SIGIO; yine de asenkron IO yapmak daha kolaydır). Bu iki sınıfın eyleme geçmesi gerekmez.
  • Bazı sinyallerin hemen ele alınması gerekmez; SIGWINCH'in beğenileri uygun olana kadar sıraya alınabilir (tıpkı X11'deki bir etkinlik gibi).
  • Zor olanları, yaptığınız şeyi yarıda keserek, ancak bir ileti dizisini silmeden onlara yanıt vermek istediğiniz şeydir. Özellikle, etkileşimli moddaki SIGINT her şeyi duyarlı bırakmalıdır.

Hala sıralamak lazım signalvs sigaction, pselect, sigwait, sigaltstack, ve diğer bit ve POSIX'e (ve POSIX olmayan) API adet bir sürü.


3

IMHO, Unix V sinyalleri ve posix konuları iyi karışmaz. Unix V 1970'tir. POSIX 1980'dir;)

İptal Noktaları vardır ve bir uygulamada sinyallere ve pthreads'e izin verirseniz, sonunda her aramanın etrafına Döngüler yazarsınız ve bu da şaşırtıcı bir şekilde EINTR'yi döndürebilir.

Dolayısıyla, Linux veya QNX üzerinde çok iş parçacıklı programlamak zorunda olduğum (birkaç) durumda yaptığım şey, tüm (bir) iş parçacığı için tüm sinyalleri gizlemekti.

Bir Unix V Sinyali geldiğinde, süreç yığını Değiştirir (bu, Unix V'de bir süreç içinde alabileceğiniz kadar eşzamanlılıktır).

Buradaki diğer yazıların da işaret ettiği gibi, Sistem'e, bu yığın değiştirmenin kurbanı olan posix iş parçacığını söylemek artık mümkün olabilir.

Bir kez, Signal işleyici iş parçacığınızı çalıştırmayı başardınız, soru kalır, sinyal bilgisini uygar bir şeye nasıl dönüştürebilirsiniz, diğer iş parçacıkları kullanabilir. İş parçacıkları arası iletişim için bir altyapı gereklidir. Yararlı bir model, iş parçacıklarınızın her birinin bazı süreç içi Mesajlaşma mekanizmaları için bir hedef olduğu aktör kalıbıdır.

Bu nedenle, diğer konuları iptal etmek veya onları (veya diğer garip şeyleri) öldürmek yerine, Sinyali Signal bağlamından Signal işleyici dizinize sıralamayı denemeli, ardından bu aktörlere anlamsal olarak yararlı mesajlar göndermek için aktör modeli iletişim mekanizmalarınızı kullanmalısınız. sinyalle ilgili bilgilere ihtiyacı olan.

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.