Linux'ta birden çok iş parçacığı ile sinyal işleme


119

Linux'ta, bir program (muhtemelen birden fazla iş parçacığı olan) SIGTERM veya SIGHUP gibi bir sinyal aldığında ne olur?

Hangi iplik sinyali keser? Birden çok iş parçacığı aynı sinyali alabilir mi? Tamamen sinyalleri işlemeye ayrılmış özel bir iş parçacığı var mı? Değilse, sinyali işleyecek iş parçacığı içinde ne olur? Sinyal işleyici rutini bittikten sonra yürütme nasıl devam eder?

Yanıtlar:


35

Bu, Linux çekirdeğinin hangi sürümünü kullandığınıza bağlı olarak biraz nüanslıdır.

2.6 posix iş parçacığı varsayarsak ve SIGTERM veya SIGHUP gönderen işletim sisteminden bahsediyorsanız, sinyal, kök iş parçacığı tarafından alınan ve işlenen işleme gönderilir. POSIX iş parçacığını kullanarak, SIGTERM'i tek tek iş parçacıklarına da gönderebilirsiniz, ancak işletim sistemi işleme sinyali gönderdiğinde ne olacağını sorduğunuzu sanıyorum.

2.6'da, SIGTERM çocuk iş parçacıklarının "temiz bir şekilde" çıkmasına neden olacaktır, burada 2.4 gibi, alt iş parçacıkları belirsiz bir durumda bırakılmıştır.


Ve bir sinyal alındığında kök dizisinin içinde ne olur? Diyelim ki SIGUSR1 için özel bir sinyal işleyici yazdım ve şimdi bu sinyali sürece gönderiyorum. Kök iş parçacığı bu sinyali alacaktır. Belki o anda bir işlevin ortasında. Ne olacak?

1
bir işleyici kurulumunuz varsa, bu bir kesme olarak kabul edilecek ve program akışı durdurulacak ve özel işleyiciniz çalıştırılacaktır. Bir kez yürütüldüğünde, normal akışı değiştirmek için hiçbir şey yapmadığınızı varsayarak (çıkış vb.) Kontrol geri dönecektir.
Alan

Bunun, IIRC'nin sistem çağrılarını kesintiye uğratmadığı SIGUSR1'e özgü olduğunu unutmayın. Örneğin, bunu SIGINT ile denediyseniz, okumayı kesebilir ve okumaya geri döndüğünüzde, akış kesintiye uğradığına dair bir hata döndürebilir.
Alan

10
"Kök iş parçacığı" ile ne kastedildiği konusunda biraz kafam karıştı. Bu, SIGTERM işleyicisinin her zaman ana iş parçacığında çalışacağı anlamına mı geliyor, yoksa herhangi bir evrede çalışabilir mi?
Stephen Nutt

3
Sinyali işlemek için rastgele bir iş parçacığı seçildiğini belirten bu cevap , cevabınızla çelişiyor.
user202729

135

pthreads(7) POSIX.1'in bir işlem paylaşım özniteliğindeki tüm iş parçacıkları gerektirdiğini açıklar:

  • sinyal eğilimleri

POSIX.1 ayrıca, her iş parçacığı için bazı özniteliklerin farklı olmasını gerektirir , örneğin:

Linux çekirdeği complete_signalrutini aşağıdaki kod bloğuna sahiptir - yorumlar oldukça kullanışlıdır:

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

Yani, sinyallerin nereye gönderileceğinden sorumlu olduğunuzu görüyorsunuz :

İşleminiz bir sinyalin eğilimini SIG_IGNveya olarak ayarladıysa, sinyal SIG_DFLtüm iş parçacıkları için göz ardı edilir (veya varsayılan - kill, core veya ignore).

Prosesiniz bir sinyalin düzenini belirli bir işleyici rutinine ayarladıysa, hangi iş parçacığının belirli iş parçacığı sinyal maskelerini kullanarak sinyalleri alacağını kontrol edebilirsiniz pthread_sigmask(3). Hepsini yönetmek için bir iş parçacığı atayabilir veya sinyal başına bir iş parçacığı oluşturabilir veya belirli sinyaller için bu seçeneklerin herhangi bir karışımını oluşturabilir veya Linux çekirdeğinin sinyali ana iş parçacığına iletme şeklindeki mevcut varsayılan davranışına güvenebilirsiniz.

Bununla birlikte, bazı sinyaller signal(7)man sayfasına göre özeldir :

Bir bütün olarak bir işlem için (örneğin, kill (2) kullanılarak gönderildiğinde ) veya belirli bir iş parçacığı için (örneğin, yürütmenin bir sonucu olarak üretilen SIGSEGV ve SIGFPE gibi belirli sinyaller ) bir sinyal üretilebilir (ve dolayısıyla beklemede) pthread_kill (3) kullanarak belirli bir evreyi hedefleyen sinyaller gibi, belirli bir makine dili talimatı iş parçacığına yöneliktir . İşleme yönelik bir sinyal, şu anda bloke edilmiş sinyale sahip olmayan ipliklerin herhangi birine gönderilebilir. Evrelerin birden fazlasının sinyali engellenmemişse, çekirdek, sinyali iletmek için rastgele bir evre seçer.

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.