(x | y) - y यह केवल x या x भी क्यों नहीं हो सकता है 0`


47

मैं एक कर्नेल कोड पढ़ रहा था, और एक स्थान पर मैंने ifकथन के अंदर एक अभिव्यक्ति देखी है

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

जहां SPINLOCK_SHARED = 0x80000000एक पूर्वनिर्धारित स्थिरांक है।

मुझे आश्चर्य है कि हमें (SPINLOCK_SHARED | 1) - 1टाइप रूपांतरण के उद्देश्य की आवश्यकता क्यों है ? अभिव्यक्ति का परिणाम 80000000-- 0x80000000 के समान होगा, है ना? अभी तक, क्यों 1 ओरिंग और 1 मामलों को घटाना?

कुछ महसूस कर रहा हूँ जैसे मुझे कुछ पाने की याद आ रही है ।।


3
#define SPINLOCK_SHARED 0x80000000
RaGa__M

1
मुझे संदेह है कि कोई कारण नहीं है। संभवतः एक कॉपी-पेस्ट चीज़। क्या आप जोड़ सकते हैं कि वास्तव में आपको यह कहाँ मिला (किस कर्नेल का कौन सा संस्करण, कौन सी फ़ाइल, आदि)।
सांडेर डे डिएकर


2
उसी स्रोत कोड फ़ाइल में भी शामिल है if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
एरिक पोस्टपिसिल

2
फिर मुझे लगता है कि हमें लेखक से यह पूछने की आवश्यकता है कि इसे क्यों बदला गया।
फन्नीडमैन

जवाबों:


1

यह सिर्फ स्पष्टता के लिए उस तरह से किया गया था, बस। ऐसा इसलिए है क्योंकि atomic_fetchadd_int () (जैसे sys / spinlock2.h) मान PRIOR को जोड़ / घटाव में लौटाता है, और यह मान _spin_lock_contested () को दिया जाता है

ध्यान दें कि सी संकलक पूरी तरह से सभी स्थिर अभिव्यक्तियों की पूर्व-गणना करता है। वास्तव में, कंपाइलर उन शर्तों के आधार पर ऑप्ट-आउट इनलाइन कोड को भी ऑप्टिमाइज़ कर सकते हैं जो उन तर्कों में प्रक्रियाओं को पारित होने पर पारित होने वाली प्रक्रिया तर्कों का उपयोग करते हैं। यही कारण है कि sys / lock.h में लॉकमग्र () इनलाइन का एक केस स्टेटमेंट होता है .... क्योंकि उस पूरे केस स्टेटमेंट को ऑप्टिमाइज़ किया जाएगा और उचित कॉल के लिए डायरेक्ट कॉल में विकसित किया जाएगा।

इसके अलावा, इन सभी लॉकिंग कार्यों में परमाणु ऑप्स का ओवरहेड परिमाण के दो या तीन आदेशों द्वारा अन्य सभी गणनाओं को बौना कर देता है।

-मैट


यह उत्तर लेखक का है !!!
Raaa__M

31

कोड में पाया जाता है _spin_lock_contested, जिसे _spin_lock_quickतब से कहा जाता है जब कोई दूसरा लॉक प्राप्त करने का प्रयास कर रहा है:

count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
    _spin_lock_contested(spin, ident, count);
}

यदि कोई प्रतियोगिता नहीं है, तो count(पिछले मूल्य) होना चाहिए 0, लेकिन यह नहीं है। इस countमान को पैरामीटर के _spin_lock_contestedरूप में valueपैरामीटर के रूप में पारित किया जाता है । इसके valueबाद ifओपी से जाँच की जाती है:

/*
 * WARNING! Caller has already incremented the lock.  We must
 *      increment the count value (from the inline's fetch-add)
 *      to match.
 *
 * Handle the degenerate case where the spinlock is flagged SHARED
 * with only our reference.  We can convert it to EXCLUSIVE.
 */
if (value == (SPINLOCK_SHARED | 1) - 1) {
    if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
        return;
}

यह ध्यान में रखते हुए कि valueपिछले मूल्य है spin->counta, और बाद वाले को पहले ही 1 से बढ़ा दिया गया है, हम spin->countaबराबर होने की उम्मीद करते हैं value + 1(जब तक कि इस बीच कुछ बदल नहीं गया है)।

तो, अगर spin->counta == SPINLOCK_SHARED | 1(के पूर्व शर्त atomic_cmpset_int) की जाँच करने से मेल खाती है अगर value + 1 == SPINLOCK_SHARED | 1, जो value == (SPINLOCK_SHARED | 1) - 1(इस बीच फिर से, अगर कुछ भी नहीं बदल गया है) के रूप में फिर से लिखा जा सकता है ।

हालांकि इसे value == (SPINLOCK_SHARED | 1) - 1फिर से लिखा जा सकता है value == SPINLOCK_SHARED, यह तुलना के इरादे को स्पष्ट करने के लिए (यानी, परीक्षण मूल्य के साथ संवर्धित पिछले मूल्य की तुलना करने के लिए) है।

या आईओडब्ल्यू। उत्तर प्रतीत होता है: स्पष्टता और कोड स्थिरता के लिए।


आपकी प्रतिक्रिया के लिए धन्यवाद, (SPINLOCK_SHARED | 1) - 1भाग को छोड़कर सब कुछ समझ में आता है और value == SPINLOCK_SHAREDमेरा विचार भी है, क्योंकि हम जाँच रहे हैं कि क्या पिछले मूल्य में साझा-ध्वज सेट है। यदि हाँ, तो ताला को विशेष में बदल दें .........
RaGa__M

1
@RaGa__M: ifचेक का आशय यह जांचना है कि क्या value + 1(जो spin->countaकि बीच में कुछ भी नहीं बदला है) समान मूल्य होना चाहिए SPINLOCK_SHARED | 1। यदि आप ifचेक को value == SPINLOCK_SHAREDइस प्रकार लिखते हैं , तो यह आशय स्पष्ट नहीं है, और यह पता लगाना बहुत कठिन होगा कि चेक का क्या अर्थ है। दोनों को SPINLOCK_SHARED | 1और - 1स्पष्ट रूप से ifचेक में रखना जानबूझकर है।
सैंडर डी डाइकर

लेकिन यह वास्तव में भ्रम पैदा कर रहा है।
RaGa__M

क्यों नहीं if (value + 1 == (SPINLOCK_SHARED | 1) )?
पाब्लो एच

ठीक है .... यह बस हो सकता है value & SPINLOCK_SHAREDजो अधिक पठनीय है।
RaGa__M

10

मुझे लगता है कि लक्ष्य शायद सबसे महत्वपूर्ण बिट को अनदेखा करना है:

  • यदि SPINLOCK_SHARED बाइनरी में व्यक्त xxx0 -> परिणाम xxx0 है
  • यदि SPINLOCK_SHARED = xxx1 -> परिणाम भी xxx0 है

शायद एक सा मुखौटा अभिव्यक्ति का उपयोग करने के लिए स्पष्ट होगा?


8
यही कोड करता है, लेकिन सवाल यह है कि आप एक परिभाषित स्थिरांक के लिए ऐसा क्यों करेंगे जिसमें कम से कम महत्वपूर्ण बिट सेट नहीं है?
सैंडर डी डाइकर

4
@SanderDeDycker क्योंकि लिनक्स कर्नेल?
लुंडिन

9
@ लुंडिन लिनक्स कर्नेल को समझने योग्य कोडिंग प्रथाओं से छूट नहीं है। काफी विपरीत।
Qix - मोनासा ने

2
@Qix यदि आप ऐसा कहते हैं। मैं लिनक्स का एक बड़ा प्रशंसक था जब तक कि मैं कोड को नहीं देखता और कर्नेल कोडिंग स्टाइल दस्तावेज़ को पढ़ता। अब मैं लिनक्स कंप्यूटरों के लिए 10 मीटर की सुरक्षा दूरी रखता हूं।
लंडिन

2
@Qix नाह मैं इसके स्रोत कोड के आधार पर इसे जज कर रहा हूं ...
लुंडिन

4

का असर

(SPINLOCK_SHARED | 1) - 1

यह सुनिश्चित करना है कि परिणाम के कम-क्रम बिट के साथ तुलना करने से पहले मंजूरी दे दी है value। मैं मानता हूं कि यह व्यर्थ लगता है, लेकिन जाहिर तौर पर कम-क्रम बिट का एक विशेष उपयोग या अर्थ है जो इस कोड में स्पष्ट नहीं है, और मुझे लगता है कि हमें यह मानना ​​होगा कि देवताओं के पास ऐसा करने का एक अच्छा कारण था। एक दिलचस्प सवाल यह होगा कि | 1) -1क्या आपके द्वारा देखे जा रहे कोडबेस में इसी पैटर्न ( ) का उपयोग किया जाता है?


2

यह थोड़ा मुखौटा लिखने का एक शानदार तरीका है। पठनीय संस्करण value == (SPINLOCK_SHARED & ~1u):।


5
हाँ, लेकिन क्यों । ओपी पूछ रहा है कि अगर SPINLOCK_SHAREDज्ञात स्थिरांक है तो ऐसा क्यों होगा । यदि वे केवल SPINLOCK_SHAREDएक मुखौटा में उपस्थित होने के लिए परीक्षण कर रहे हैं , तो क्यों नहीं if (value & SPINLOCK_SHARED)?
Qix - मोनासा ने

4
value == (SPINLOCK_SHARED & ~1u)समतुल्य नहीं है क्योंकि value == (SPINLOCK_SHARED | 1) - 1यदि प्रकार की SPINLOCK_SHAREDतुलना में व्यापक है तो भी काम करता है unsigned
एरिक पोस्टपिसिल

4
ईमानदारी से, मुझे यकीन नहीं है कि & ~1uकोई भी स्पष्ट है। मैंने & 0xFFFFFFFEअपने उत्तर में सुझाव देने की सोची लेकिन महसूस किया कि यह वास्तव में स्पष्ट नहीं है। आपके सुझाव में संक्षिप्तता का लाभ है, हालांकि। :-)
बॉब जार्विस - मोनिका

6
@ लुंडिन: हम नहीं जानते कि यह होगा 0x80000000। ओपी ने कहा है कि इसे परिभाषित किया गया है #define SPINLOCK_SHARED 0x80000000, लेकिन यह अंदर हो सकता है #if…#endifऔर एक अलग परिभाषा का उपयोग अन्य परिस्थितियों में किया जाता है, या इस कोड के लेखक को यह काम करने का इरादा हो सकता है, भले ही परिभाषा संपादित हो या कोड अन्य हेडर के साथ संकलित हो। इसे अलग तरह से परिभाषित करें। बावजूद, कोड के दो टुकड़े खुद के बराबर नहीं हैं।
एरिक पोस्टपिसिल

2
@ BobJarvis-ReinstateMonica यह उन लोगों के लिए बहुत स्पष्ट है जो हर दिन बिटवाइज़ ऑपरेटरों के साथ काम करते हैं। नियमित अंकगणित के साथ बिटवाइज़ को मिक्स करना भ्रामक है।
लुंडिन

0

अधिकांश इस तरह कई अतिरिक्त मामलों को संभालने के लिए किया जाता है। उदाहरण के लिए, इस मामले में, हम कहते हैं कि SPINLOCK_SHARED1 नहीं हो सकता है:

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0

2
यह समझ में आता है लेकिन, हालांकि यह वास्तव में प्रश्न से स्पष्ट नहीं है, ऐसा लगता है SPINLOCK_SHAREDकि एक परिभाषित स्थिरांक है और परीक्षण किया गया चर है value। इस मामले में मिस्टी बनी हुई है।
रॉबर्टो कैबोनी

आपके उत्तर के लिए धन्यवाद, लेकिन मुझे लगता है कि मूल मामले में SPINLOCK_SHARED 0x01 नहीं है, आपने | 1) - 1भाग को रखा , जब SPINLOCK_SHARED ने पकड़े 0x80000000कि इसका प्रभाव क्या होगा | 1) - 1?
Raaa__M

एकमात्र कारण जो मैं सोच सकता था, वह यह है कि वे SPINLOCK_SHAREDभविष्य में बदले जाने से बचना चाहते थे । लेकिन यह बिल्कुल स्पष्ट नहीं है। मैं कर्नेल देवों में लिखूंगा और स्पष्टीकरण टिप्पणी करने के लिए या अभिव्यक्ति को फिर से व्यवस्थित करने के लिए कहूंगा ताकि यह स्व-दस्तावेज हो।
क्यूक्स - मोनासा ने १२
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.