2014-07-08 10 views
11

मुझे सही संकेतों को पकड़ने के लिए थ्रेड प्राप्त करने में समस्या हो रही है।यूनिक्स पथ्रेड और सिग्नल: प्रति थ्रेड सिग्नल हैंडलर

उदाहरण के लिए

,

मैं पहली बार एक मुख्य थ्रेड प्रारंभ (टीआईडी ​​1)।

फिर, यह SIGUSR1 के लिए signal(2) का उपयोग करके SIGUSR1 के लिए सिग्नल हैंडलर सेट करता है।

मुख्य थ्रेड 2.

धागा 2 में, मैं SIGUSR1function2() करने के लिए signal(2) प्रयोग करने के लिए एक संकेत हैंडलर रजिस्टर टीआईडी ​​साथ, एक नया धागा बनाता है।

थ्रेड 1 फिर थ्रेड 3 (टिड 3) बनाता है।

धागा 3 से, मैं pthread_kill(1, SIGUSR1) का प्रयोग कर एक संकेत भेजने के लिए सूत्र में बाँधना 1.

हालांकि, function2() बुलाया जाता है, function1() नहीं।

क्या यह व्यवहार इरादा है, या क्या मुझे सिग्नल हैंडलर को काम करने के लिए कुछ बदलने की ज़रूरत है?

संपादित करें: मैंने कुछ डिबगिंग किया है और यह पता चला है कि सिग्नल थ्रेड 1 पर भेजा जा रहा है, हालांकि function2() किसी कारण से थ्रेड 1 से कॉल किया जा रहा है। क्या इसके आसपास कोई कार्य है?

+3

सिग्नल प्रति प्रक्रिया कॉल है, प्रति थ्रेड एक नहीं, अगर आप इसे कॉल करते हैं तो यह प्रक्रिया में सभी धागे के लिए हैंडलर सेट करता है। संकेत और धागे एक जटिल विषय है। आप वास्तव में क्या करना चाहते हैं इसके बारे में पूछने से बेहतर हो सकता है। –

+3

एक बहुप्रचारित कार्यक्रम में 'सिग्नल' का उपयोग करना अनिवार्य रूप से अपरिभाषित व्यवहार है। यह मैनुअल में ऐसा कहता है। –

+0

स्रोत कोड कृपया। –

उत्तर

7

इसके अलावा alk's answer रहे हैं:

आप एक प्रति-धागा समारोह का उपयोग कर सकते एक निश्चित सिग्नल वितरित होने पर, प्रति-थ्रेड तरीके से, कौन सा फ़ंक्शन निष्पादित किया जाता है, यह चुनने के लिए सूचक।

नोट: सिग्नल पर धागा वितरित किए जाते हैं जो स्पष्ट रूप से इसकी डिलीवरी को अवरुद्ध नहीं कर रहा है। यह उसमें बदलाव नहीं करता है। आपको अभी भी pthread_kill() या सिग्नल को एक विशिष्ट थ्रेड पर निर्देशित करने के लिए समान तंत्र का उपयोग करने की आवश्यकता है; सिग्नल जो उठाए जाते हैं या प्रक्रिया में भेजे जाते हैं (एक विशिष्ट थ्रेड के बजाए), अभी भी एक यादृच्छिक धागे द्वारा नियंत्रित किए जाएंगे (उनमें से जो इसे अवरुद्ध नहीं करते हैं)।

मैं किसी भी उपयोग के मामले के बारे में नहीं सोच सकता जहां मैं व्यक्तिगत रूप से इस दृष्टिकोण को प्राथमिकता दूंगा; इस प्रकार अब तक कुछ और तरीका रहा है, कुछ और आसान और बेहतर है।इसलिए, यदि आप वास्तविक एप्लिकेशन के लिए ऐसा कुछ लागू करने पर विचार कर रहे हैं, तो कृपया वापस जाएं और अपने एप्लिकेशन तर्क पर पुनर्विचार करें।

लेकिन, के बाद से तकनीक संभव है, यहाँ मैं इसे कैसे लागू हो सकता है:

#include <signal.h> 

/* Per-thread signal handler function pointer. 
* Always use set_thread_SIG_handler() to change this. 
*/ 
static __thread void (*thread_SIG_handler)(int, siginfo_t *, void *) = (void *)0; 

/* Process-wide signal handler. 
*/ 
static void process_SIG_handler(int signum, siginfo_t *info, void *context) 
{ 
    void (*func)(int, siginfo_t *, void *); 

#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) 
    func = __atomic_load_n(&thread_SIG_handler, __ATOMIC_SEQ_CST); 
#else 
    func = __sync_fetch_and_add(&thread_SIG_handler, (void *)0); 
#endif 

    if (func) 
     func(signum, info, context); 
} 

/* Helper function to set new per-thread signal handler 
*/ 
static void set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *)) 
{ 
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) 
    __atomic_store_n(&thread_SIG_handler, func, __ATOMIC_SEQ_CST); 
#else 
    void (*oldfunc)(int, siginfo_t *, void *); 
    do { 
     oldfunc = thread_SIG_handler; 
    } while (!__sync_bool_compare_and_swap(&thread_SIG_handler, oldfunc, func)); 
#endif 
} 

/* Install the process-wide signal handler. 
*/ 
int install_SIG_handlers(const int signum) 
{ 
    struct sigaction act; 
    sigemptyset(&act.sa_mask); 
    act.sa_sigaction = process_SIG_handler; 
    act.sa_flags = SA_SIGACTION; 
    if (sigaction(signum, &act, NULL)) 
     return errno; 
    return 0; 
} 

मैं ऊपर की तरह है, क्योंकि यह pthreads की आवश्यकता नहीं है, और बहुत मजबूत और विश्वसनीय है। उस प्रीप्रोसेसर तर्क के कारण दृश्य गड़बड़ी के अलावा, परमाणु बिल्ट-इन्स की कौन सी शैली का चयन किया जाता है, यह बहुत आसान है, अगर आप इसे ध्यान से देखते हैं।

जीसीसी 4.7 और बाद में सी ++ 11-जैसे __atomic built-ins, पुराने जीसीसी संस्करण और अन्य कंपाइलर्स (आईसीसी, पाथस्केल, पोर्टलैंड समूह) प्रदान करते हैं __sync legacy built-ins प्रदान करते हैं। थ्रेड-लोकल स्टोरेज के लिए __thread keyword समान रूप से सभी मौजूदा POSIX-y सिस्टम में उपलब्ध होना चाहिए।

#include <pthread.h> 
#include <signal.h> 
#include <errno.h> 

static pthread_key_t thread_SIG_handler_key; 

static void process_SIG_handler(int signum, siginfo_t *info, void *context) 
{ 
    void (*func)(int, siginfo_t *, void *); 

    *((void **)&func) = pthread_getspecific(thread_SIG_handler_key); 
    if (func) 
     func(signum, info, context); 
} 

static int set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *)) 
{ 
    sigset_t block, old; 
    int result; 

    sigemptyset(&block); 
    sigaddset(&block, SIG); /* Use signal number instead of SIG! */ 
    result = pthread_sigmask(SIG_BLOCK, &block, &old); 
    if (result) 
     return errno = result; 

    result = pthread_setspecific(thread_SIG_handler_key, (void *)func); 
    if (result) { 
     pthread_sigmask(SIG_SETMASK, &old, NULL); 
     return errno = result; 
    } 

    result = pthread_sigmask(SIG_SETMASK, &old, NULL); 
    if (result) 
     return errno = result; 

    return 0; 
} 

int install_SIG_handlers(const int signum) 
{ 
    struct sigaction act; 
    int result; 

    result = pthread_key_create(&thread_SIG_handler_key, NULL); 
    if (result) 
     return errno = result; 

    sigemptyset(&act.sa_mask); 
    act.sa_sigaction = process_SIG_handler; 
    act.sa_flags = SA_SIGACTION; 
    if (sigaction(signum, &act, NULL)) 
     return errno; 

    return 0; 
} 

मुझे लगता है कि इस तरह से कोड करने के लिए निकटतम वास्तविक जीवन बराबर है कि मैं वास्तव कर दिया है:

आप एक प्राचीन प्रणाली है, या मानक अनुपालन पर जोर देते हैं, तो निम्न कोड बराबर व्यवहार करना चाहिए था कभी भी इस्तेमाल किया जाता है, वह एक है जहां मैंने एक रीयलटाइम सिग्नल (SIGRTMIN+0) को एक थ्रेड के रूप में अवरुद्ध किया है, एक परावर्तक के रूप में: यह अवरोधक I/O को बाधित करने के लिए, कई कार्यकर्ता थ्रेडों में एक और रीयलटाइम सिग्नल (SIGRTMIN+1) भेजा गया है। (यह एक वास्तविक समय संकेत के साथ ऐसा करना संभव है, लेकिन दो संकेत मॉडल को लागू करने और आसान करने के लिए बनाए रखने के लिए आसान है।)

इस तरह के संकेत प्रतिबिंब या फैनआउट कभी कभी उपयोगी है, और यह से अलग नहीं है यह दृष्टिकोण। अपने स्वयं के प्रश्न की गारंटी देने के लिए काफी अलग, हालांकि, अगर कोई दिलचस्पी लेता है।

+0

आप मेरे डिजाइन पर पुनर्विचार करने के बारे में बिल्कुल सही थे। मैंने pthread_cancel का उपयोग करने का विकल्प चुना है क्योंकि यह मेरी आवश्यकताओं को अच्छी तरह से फिट करने लग रहा था। हालांकि, आपकी लिस्टिंग में एक छोटी सी समस्या हो सकती है। 'pthread_getspecific() 'मैन पेज के अनुसार async-signal सुरक्षित नहीं है, और मुझे नहीं लगता कि' __thread' संग्रहण पहुंच या तो है। – tomKPZ

+0

@ user1887231: प्रैक्टिस में, [वे हैं] (http://sourceware.org/ml/libc-alpha/2012-06/msg00372.html)। मानकों ने अभी तक एसिंक-सिग्नल सुरक्षित थ्रेड-विशिष्ट चर के मुद्दे को संबोधित नहीं किया है। कम से कम जीएनयू टूल्स के साथ, अभ्यास में * pthread_getspecific() 'और' __thread' चर दोनों एसिंक-सिग्नल सुरक्षित * हैं। (यहां, केवल सिग्नल हैंडलर * थ्रेड-विशिष्ट चर को पढ़ता है, इसलिए "आउट-ऑफ-टीएलएस-स्टोरेज" मामले लागू नहीं होते हैं।) यदि आप इसके बारे में चिंता करते हैं, तो मुझे बताएं, और मैं एक कामकाज को स्वीकार करूंगा (मुझे लगता है कि मैं एक तरह से जानता हूँ)। –

4

"प्रति-थ्रेड" सिग्नल हैंडलर इंस्टॉल करना संभव नहीं है।

man 7 signal (मेरे द्वारा जोर) से:

संकेत स्वभाव एक प्रति प्रक्रिया विशेषता है: एक बहु आवेदन में, एक विशेष संकेत के स्वभाव सभी थ्रेड के लिए ही है।

हालांकि यह , एक अलग धागा करने के लिए प्रत्येक संकेत प्रकार निर्देशित करने के लिए एक "प्रति-सूत्र" के आधार पर संकेत प्रकार के किसी भी संख्या के स्वागत के बाहर मास्किंग द्वारा संभव है।

कैसे एक विशिष्ट थ्रेड के लिए संकेत प्रकार का एक सेट निर्देशित करने के लिए आप इस जवाब पर देखने के लिए पसंद कर सकते हैं पर: https://stackoverflow.com/a/20728819/694576

संबंधित मुद्दे