2013-01-20 59 views
5

सबसे पहले, मुझे पता है कि म्यूटेक्स को सामान्य रूप से एसिंक-सुरक्षित नहीं माना जाता है। यह सवाल sigprocmask के उपयोग से संबंधित है ताकि मल्टीक्स्रेड प्रोग्राम में एसिंक सिग्नल और सिग्नल हैंडलर के साथ म्यूटेक्स सुरक्षित हो सके।एसिंक संकेतों के साथ म्यूटेक्स सुरक्षा की गारंटी

struct { int a, b; } gvars; 

void sigfoo_handler(int signo, siginfo_t *info, void *context) { 
    if(gvars.a == 42 || gvars.b == 13) { 
     /* run a chained signal handler */ 
    } 
} 

/* called from normal code */ 
void update_gvars(int a, int b) { 
    gvars.a = a; 
    gvars.b = b; 
} 

gvars एक वैश्विक चर जो एक एकल sig_atomic_t में फिट करने के लिए बहुत बड़ी है है:

मैं धारणात्मक निम्नलिखित की तरह कुछ कोड है। यह सामान्य कोड द्वारा अद्यतन किया जाता है और सिग्नल हैंडलर से पढ़ा जाता है। नियंत्रित कोड एक जंजीर सिग्नल हैंडलर है, और इसलिए इसे सिग्नल हैंडलर संदर्भ में चलाना चाहिए (यह info या context का उपयोग कर सकता है)। नतीजतन, gvars तक पहुंच सभी प्रकार के सिंक्रनाइज़ेशन तंत्र के माध्यम से नियंत्रित की जानी चाहिए। जटिल मामलों, कार्यक्रम बहुप्रचारित है, और किसी भी धागे को SIGFOO प्राप्त हो सकता है।

प्रश्न:sigprocmask (या pthread_sigmask) और pthread_mutex_t के संयोजन से, यह संभव करने के लिए गारंटी तुल्यकालन, निम्नलिखित की तरह कोड का उपयोग कर रहा है?

struct { int a, b; } gvars; 
pthread_mutex_t gvars_mutex; 

void sigfoo_handler(int signo, siginfo_t *info, void *context) { 
    /* Assume SIGFOO's handler does not have NODEFER set, i.e. it is automatically blocked upon entry */ 
    pthread_mutex_lock(&gvars_mutex); 
    int cond = gvars.a == 42 || gvars.b == 13; 
    pthread_mutex_unlock(&gvars_mutex); 

    if(cond) { 
     /* run a chained signal handler */ 
    } 
} 

/* called from normal code */ 
void update_gvars(int a, int b) { 
    sigset_t set, oset; 
    sigemptyset(&set); 
    sigaddset(&set, SIGFOO); 
    pthread_sigmask(SIG_BLOCK, &set, &oset); 
    pthread_mutex_lock(&gvars_mutex); 
    gvars.a = a; 
    gvars.b = b; 
    pthread_mutex_unlock(&gvars_mutex); 
    pthread_sigmask(SIG_SETMASK, &oset, NULL); 
} 

तर्क निम्नलिखित के रूप में चला जाता है: sigfoo_handler भीतर, SIGFOO अवरुद्ध है तो यह pthread_mutex_lock को बाधित नहीं कर सकते हैं। update_gvars के भीतर, SIGFOOpthread_sigmask-संरक्षित महत्वपूर्ण क्षेत्र के दौरान वर्तमान धागे में नहीं उठाया जा सकता है, और इसलिए यह pthread_mutex_lock को बाधित नहीं कर सकता है। मान लें कि अन्य सिग्नल (और हम हमेशा किसी अन्य सिग्नल को अवरुद्ध कर सकते हैं जो समस्याग्रस्त हो सकता है), ताला/अनलॉक हमेशा मौजूदा थ्रेड पर सामान्य, अनियंत्रित फैशन में आगे बढ़ना चाहिए, और लॉक/अनलॉक के उपयोग को सुनिश्चित करना चाहिए कि अन्य धागे हस्तक्षेप नहीं करते हैं। क्या मैं सही हूं, या मुझे इस दृष्टिकोण से बचना चाहिए?

उत्तर

1

आप स्पष्ट रूप से जानते हैं कि आप sig_atomic_t के उल्लेख के साथ अपरिभाषित व्यवहार क्षेत्र में हैं। ऐसा कहा जा रहा है कि, एकमात्र तरीका यह है कि मैं आधुनिक यूनिक्स जैसी प्रणालियों पर काम नहीं कर रहा यह सटीक उदाहरण है यदि सिग्नल SA_NODEFER के साथ स्थापित किया गया था।

म्यूटेक्स विभिन्न धागे (सिग्नल हैंडलर को दूसरे धागे में चलाने के साथ) के बीच उचित सिंक्रनाइज़ेशन सुनिश्चित करने के लिए पर्याप्त है और सिग्मास्क इस थ्रेड में सिग्नल हैंडलर को म्यूटेक्स को दोबारा शुरू करने से रोक देगा।

कहा जा रहा है कि आप सिग्नल हैंडलर के अंदर ताले के साथ गहरे पानी में हैं। एक सिग्नल हैंडलर पर्याप्त सुरक्षित हो सकता है, लेकिन यदि आपके पास दो सिग्नल हैंडलर अलग-अलग ताले के साथ एक ही चाल कर रहे हैं तो आप लॉक ऑर्डरिंग डेडलॉक्स के साथ समाप्त होते हैं। थ्रेड सिग्मास्क के बजाय प्रक्रिया सिग्मास्क लागू करके इसे कुछ हद तक कम किया जा सकता है। सिग्नल हैंडलर में एक साधारण डीबगिंग fprintf निश्चित रूप से लॉक ऑर्डरिंग का उल्लंघन करेगा, उदाहरण के लिए।

मैं वापस अपने आवेदन को फिर से डिजाइन कर दूंगा क्योंकि सिग्नल हैंडलर में इस तरह की चीजें एक संकेत है कि यह बहुत जटिल हो रही है और तोड़ना बहुत आसान है। एक sig_atomic_t को छूने वाले सिग्नल हैंडलर सी मानक में एकमात्र परिभाषित चीज हैं क्योंकि कुछ और सही होने की विस्फोट जटिलता की वजह से।

+0

यदि सिग्नल 'SA_NODEFER' के साथ सेट किया गया है, तो मैं हैंडलर के भीतर ही 'sigprocmask' का उपयोग उसी तरह से करने में सक्षम होना चाहिए, नहीं? – nneonneo

+1

इसके अलावा, प्रक्रिया सिग्मास्क प्रश्न से बाहर हैं, क्योंकि दो धागे से एक साथ 'सिगप्रोकमास्क' का उपयोग करना निश्चित रूप से नो-नो है। मुझे संदेह है कि इससे निपटने का सबसे अच्छा तरीका थ्रेड सिग्मास्क में सभी संकेतों को अवरुद्ध करना होगा यदि एकाधिक सिग्नल हैंडलर थे। – nneonneo

+0

यदि मैं स्पष्ट रूप से कर सकता हूं, तो मैं एप्लिकेशन को फिर से डिजाइन कर दूंगा, लेकिन मेरे मामले में ऐसा कुछ क्यों जरूरी है, इसके बहुत अच्छे कारण हैं। – nneonneo

1

मैं इस पत्र https://www.cs.purdue.edu/homes/rego/cs543/threads/signals.pdf द्वारा

  1. सुरक्षित रूप से sig संचालकों में के रूप में-असुरक्षित कोड चल चर्चा है कि (कम कुशल के रूप में पता लगाया) या
  2. सामान्य संदर्भ कोड के रूप में-असुरक्षित ब्लॉकों में संकेत बाहर मास्किंग पाया एक वैश्विक sig_atomic अस्थिर झंडा है कि अगर सेट दर्ज किया जा रहा से हैंडलर में के रूप में-असुरक्षित कोड से बचाता है के साथ सामान्य संदर्भ कोड के रूप में-असुरक्षित ब्लॉक की रक्षा (कुशल के रूप में पता लगाया)

यह दृष्टिकोण पी के हिस्से को संतुष्ट करता है OSIX मानक है कि का कहना है कि sig-संचालकों में के रूप में-असुरक्षित कार्यों बुला रहा है केवल असुरक्षित माना यदि sighandler एक के रूप में असुरक्षित समारोह (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03_03: समारोह सूची के बाद 1 पैरा के लिए नीचे स्क्रॉल) व्यवधान

मुझे लगता है कि तुम क्या 'फिर से यहाँ के साथ कर रही अनिवार्य रूप से इस विचार का एक और अधिक सुक्ष्म संस्करण है, जब से तुम किसी भी रूप-असुरक्षित कोड बल्कि साथ संघर्ष से एक sig-हैंडलर से

pthread_mutex_lock(&gvars_mutex); 
int cond = gvars.a == 42 || gvars.b == 13; 
pthread_mutex_unlock(&gvars_mutex); 

रन रोकने के लिए कोशिश नहीं कर रहे इस म्यूटेक्स और इन चर से निपटने वाले इस समान/समान AS-unsafe कोड के साथ।

दुर्भाग्यवश, POSIX में केवल सिग्नल-सुरक्षा की कोड-केवल अवधारणा होती है: एक फ़ंक्शन या तो सुरक्षित या असुरक्षित है, इसके तर्कों के बावजूद।

हालांकि, IMO, एक सेमाफोर/म्युटेक्स किसी भी डेटा पर काम करने के लिए कोई अच्छा कारण है या ओएस म्युटेक्स में निहित के अलावा अन्य संभालती है/सेमाफोर वे पारित कर दिया हैं, इसलिए मैंने एक संकेत हैंडलर से sem_wait(&sem)/pthread_mutex_lock(&mx); बुला लगता है चाहिए सुरक्षित होने के लिए यदि यह sem_wait/pthread_mutex_lock के साथ एक ही म्यूटेक्स पर कभी भी संघर्ष करने की गारंटी नहीं है, भले ही POSIX मानक तकनीकी रूप से कहता है कि यह सुरक्षित नहीं होना चाहिए (स्वागत से अधिक काउंटर-तर्क)।

+1

खैर, मेरा तर्क है कि आप सही हैं "हम इसे उत्पादन में इस्तेमाल करते हैं और कुछ नहीं तोड़ दिया": डी। लेकिन, निश्चित रूप से, किसी भी शुद्धता को केवल भाग्य के लिए तैयार किया जा सकता है (उदाहरण के लिए कर्नेल जो सही तरीके से व्यवहार करने के लिए होता है, libc जो सही तरीके से व्यवहार करता है, इत्यादि) मानकों के अनुसार कड़ाई से सही होने के बजाय। – nneonneo