मैं लंबे समय से लिनक्स पर सी ++ विकसित कर रहा हूं। और जब मैं संदेश/कार्य कतार को संसाधित करने वाला कुछ स्वतंत्र मॉड्यूल विकसित करता हूं, तो मैं हमेशा संदेश/कार्य हानि से बचने के लिए SIGINT सिग्नल को संसाधित करता हूं। यहाँ मेरे कोड का एक उदाहरण है:

volatile sig_atomic_t sig = 0;

void sig_handler(int signal)
{
    sig = 1;
}

int main()
{
    signal(SIGINT,sig_handler);

    msg_queue = init_msg_queue();
    init_receiving_msg_thread();    // start a thread to receive msgs and push them into msg_queue
    while(!sig) {
        process_msg(msg_queue.top());    // process the first msg in the queue
        msg_queue.pop();    // remove the first msg
    }
    stop_receiving_msg_thread();
    process_all_msgs(msg_queue);
    return 0;
}

खैर, कोड का यह टुकड़ा सरल है: यदि सिग्नल SIGINT पर कब्जा कर लिया गया है, तो संदेश प्राप्त करना बंद कर दें, कतार में छोड़े गए सभी संदेशों को संसाधित करें और वापस लौटें। अन्यथा, कोड अनंत काल में रहेगा।

मुझे लगा कि sig_atomic_t कोई काला जादू है। क्योंकि मेरी समझ के अनुसार, फ़ंक्शन sig_handler एक रीएंट्रेंट फ़ंक्शन होना चाहिए, जिसका अर्थ है कि यह कोई स्थिर या वैश्विक गैर-स्थिर डेटा नहीं रख सकता है: रीएंट्रेंट फंक्शन वास्तव में क्या है?

इसलिए मैंने हमेशा सोचा कि वैश्विक चर के बजाय sig_atomic_t कुछ मुश्किल चीजें थीं।

लेकिन आज मैंने यह लिंक पढ़ा: sig_atomic_t वास्तव में कैसे काम करता है?, जिसने मुझे बताया कि sig_atomic_t केवल एक टाइपिफ़ के अलावा और कुछ नहीं है, जैसे कि एक इंट। तो ऐसा लगता है कि sig_atomic_t sig केवल एक वैश्विक चर है।

अब मैं उलझन में हूँ।

क्या ऊपर दिए गए मेरे कोड ने sig_atomic_t का सही इस्तेमाल किया? यदि नहीं, तो क्या आप कृपया मुझे एक सही उदाहरण दिखा सकते हैं? अगर मेरा कोड सही है, तो मैंने क्या गलत समझा? sig_atomic_t वैश्विक चर नहीं है? या एक वैश्विक चर का उपयोग पुनर्विक्रय समारोह में किया जा सकता है? या फंक्शन sig_handler नॉन-रीएंट्रेंट फंक्शन हो सकता है?

2
Yves 6 जिंदा 2021, 10:09
मैं सिर्फ इतना कहना चाहता हूं कि यह एक बहुत अच्छा और अच्छी तरह से लिखा गया प्रश्न है।
 – 
StealthBadger747
6 जिंदा 2021, 10:27

1 उत्तर

सबसे बढ़िया उत्तर

volatile sig_atomic_t का आपका उपयोग सही है।

signal(3p) का मैनपेज निम्नलिखित कहता है:

   "the behavior is undefined if the signal handler refers to any
   object other than errno with static storage duration other than
   by assigning a value to an object declared as volatile
   sig_atomic_t," ...

तो volatile sig_atomic_t में यह क्षमता क्यों है जबकि अन्य चर असुरक्षित हैं?

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

एक सच्चे परमाणु प्रकार को वास्तव में सीपीयू द्वारा विशेष रूप से नियंत्रित किया जाता है जहां यह सुनिश्चित करेगा कि केवल एक कोर (सीपीयू) एक संपूर्ण ऑपरेशन कर सकता है (कुछ जोड़तोड़ को पूरा करने के लिए कई निर्देश लेते हैं) इससे पहले कि दूसरा सीपीयू (या प्रक्रिया) उस डेटा में हेरफेर कर सके। दूसरी ओर sig_atomic_t उस हार्डवेयर गारंटी को प्रदान नहीं करता है, बल्कि यह सुनिश्चित करता है कि उस पर किए गए किसी भी ऑपरेशन (पढ़ने/लिखने) को एक ही निर्देश के साथ किया जाएगा, इस प्रकार उस फ़ंक्शन के पुनर्विक्रेता की क्षमता उस मूल्य के पूरा होने में बाधा डालने के लिए हेरफेर समाप्त हो जाता है।

0
StealthBadger747 6 जिंदा 2021, 10:45
धन्यवाद। यह मदद करता है। अब मैं इस मुद्दे को इस तरह समझाता हूं: int को एक बार में पढ़ने और लिखने की गारंटी दी जा सकती है। लेकिन अन्य प्रकार, जैसे long, CustomStruct नहीं कर सकते। इस मामले में, लोग कहते हैं: किसी भी रीएंट्रेंट फ़ंक्शन में sig_atomic_t को छोड़कर किसी भी अन्य वैश्विक चर का उपयोग न करें, यह सुनिश्चित करने के लिए कि सब कुछ ठीक हो जाएगा, डेवलपर को मदद के साथ रीएंट्रेंट फ़ंक्शन में चर का उपयोग करते समय बहुत सावधान रहने की आवश्यकता नहीं है। sig_atomic_t का। हो सकता है किसी दिन, int को एक बार में पढ़ने और लिखने की गारंटी नहीं दी जा सकती, उस समय, sig_atomic_t int के साथ समान नहीं होगा...
 – 
Yves
6 जिंदा 2021, 11:21
मुझे अभी-अभी sig_atomic_t के बारे में स्रोत कोड मिला: code.woboq.org/userspace/glibc/signal/bits/types/…, हम __sig_atomic_t पर डबल-क्लिक कर सकते हैं और इसकी परिभाषा प्राप्त कर सकते हैं: typedef int __sig_atomic_t;
 – 
Yves
6 जिंदा 2021, 11:23
बेशक, जैसा कि आपने कहा, it is guaranteed to be read and written in one go का मतलब थ्रेड सेफ नहीं है। मैं यह समझ सकता हूँ।
 – 
Yves
6 जिंदा 2021, 11:33
आपकी पहली टिप्पणी के संबंध में। मैं आपके तर्क से सहमत हूं। लेकिन शायद ऐसी संभावनाएं हैं जहां कुछ सीपीयू पर, शायद 8 बिट सीपीयू जहां int एक निर्देश के साथ संभालने के लिए बहुत बड़ा होगा। इस प्रकार इस टाइपपीफ का उपयोग करके यह स्पष्ट हो जाता है कि इस चर के साथ क्या होना चाहिए। इसके अलावा, मैं तर्क दूंगा कि यह sig_atomic_t का उपयोग करने के लिए सिर्फ एक अच्छी शैलीगत पसंद है क्योंकि यह स्पष्ट करता है कि यह चर का एक सुरक्षित उपयोग है।
 – 
StealthBadger747
6 जिंदा 2021, 12:07
मुझे यह भी उल्लेख करना चाहिए कि आपके द्वारा संदर्भित परिभाषा केवल ग्लिब में गारंटीकृत है। हालांकि मुझे यकीन है कि अधिकांश अन्य libc कार्यान्वयनों की एक ही परिभाषा होगी। हालांकि मुझे यकीन नहीं है कि यह सी मानक या पॉज़िक्स मुद्दा है या नहीं, जिसका अर्थ यह होगा कि यह चाहिए हर जगह समान होना चाहिए।
 – 
StealthBadger747
6 जिंदा 2021, 12:14