2012-10-03 11 views
8

मानक कहता है: "प्रकार का धागा :: आईडी प्रदान करता है ... सभी थ्रेड ऑब्जेक्ट्स के लिए एक अलग मूल्य जो निष्पादन के धागे का प्रतिनिधित्व नहीं करता है"। क्या यह operator== के संबंध में एक एकल/विशिष्ट मान है, या यह वास्तविक बिटवाई-सिंगल/विशिष्ट मान है?std :: thread :: id के लिए आवश्यकताएँ। क्या यह परमाणु हो सकता है?

प्रश्न का कारण: MSVC2012 का std::thread::id::id() अपने खेतों में से एक में कचरा छोड़ देता है, और यह std::atomic<std::thread::id> पर तुलना-विनिमय की तुलना करता है (क्योंकि बाद में बिटवाई तुलनाओं पर निर्भर करता है)।

std::atomic<std::thread::id> पहले स्थान पर एक कानूनी निर्माण है?

संपादित करें: संदर्भ के लिए, कोड इस प्रकार है:

while(!worker_id.compare_exchange_weak(no_id = thread_id_type(), self_id)) 
    sleep(); 

उत्तर

10

सबसे पहले, std::atomic<std::thread::id> कानूनी है: std::thread::id को तुलनीय रूप से कॉपी करने योग्य (30.3.1.1p2) होना आवश्यक है, जो std::atomic<> (2 9 .5p1) की आवश्यकताओं को पूरा करता है।

हालांकि, यह एक अपारदर्शी वर्ग है, इसलिए ऐसी कोई आवश्यकता नहीं है कि समान वस्तुओं की बिट पैटर्न समान समान हो।

परिणामस्वरूप, यदि आप compare_exchange_weak या compare_exchange_strong का उपयोग करते हैं तो यह बराबर की तुलना करने वाले मानों के लिए असफल हो सकता है।

इस प्रकार, सलाह एक पाश में compare_exchange_weak, उपयोग करने के लिए पिछले यात्रा के परिणाम के रूप expected मूल्य छोड़ने है।

आपके मामले में, अर्थ विज्ञान मैं अपने पाश से व्याख्या कर रहे हैं: जबकि worker_id पाशन रखना एक और धागा की आईडी है, या worker_idstd::thread::id था, लेकिन विनिमय विफल रहा है। आप निम्न के साथ इस लक्ष्य को हासिल कर सकते हैं:

no_id=std::thread::id(); 
while((no_id!=std::thread::id()) || 
     !worker_id.compare_exchange_weak(no_id, self_id)){ 
    if(no_id!=std::thread::id()) no_id=std::thread::id(); 
    sleep(); 
} 

या

no_id=std::thread::id(); 
while(!worker_id.compare_exchange_weak(
      (no_id!=std::thread::id())?(no_id=std::thread::id())?no_id, self_id)) 
    sleep(); 

यानी केवल no_id मूल्य बदल अगर यह नहींstd::thread::id() है।

+0

धन्यवाद।'No_id' को चुनिंदा रीसेट करना एक अच्छी चाल है, अब मुझे आश्चर्य है कि मैंने इसे क्यों नहीं देखा :) – vpozdyayev

+0

लेकिन शायद आप केवल नींद को कॉल करना चाहते हैं अगर "no_id! = Std :: thread :: id() " पाश में। – cmeerw

+0

@cmeerw हाँ --- मैं बस जितना संभव हो सके vpozdyayev के लूप को दोहराने की कोशिश कर रहा था। यदि 'compar_exchange_weak'" उग्रतापूर्वक "विफल रहता है तो आप ज्यादातर मामलों में प्रतीक्षा किए बिना तत्काल लूप करना चाहते हैं। –

5

यह LWG924 में चर्चा की गई। अनिवार्य रूप से, आप compare_exchange_strong का उपयोग नहीं कर सकते हैं, लेकिन आप एक लूप में compar_exchange_weak का उपयोग करने में सक्षम होना चाहिए, उदा।

expected = current.load(); 
do { 
    desired = function(expected); 
} while (!current.compare_exchange_weak(expected, desired)); 

संपादित: बिना सोचे मूल्य को रीसेट लूप के उद्देश्य धरा - आपूर्ति कोड के आधार पर, मुझे लगता है कि सबसे अच्छा समाधान तो होगा:

no_id = std::thread::id(); 
while(!worker_id.compare_exchange_weak(no_id, self_id)) 
{ 
    if (no_id != std::thread::id()) 
    { 
    sleep(); 
    no_id = std::thread::id(); 
    } 
} 
+0

मैं लूप में 'compar_exchange_weak' का उपयोग कर रहा हूं और, दुख की बात है, इससे मदद नहीं मिलती है। बीटीडब्ल्यू, यहां मुद्दा अनियमित फ़ील्ड है, पैडिंग नहीं (आपके लिंक में "संबंधित लेकिन अलग करने योग्य समस्या" के रूप में उल्लिखित)। मुझे memcmp semantics के बारे में नोट 29.6.5/26 और तुलना_exchange_weak तेजी से कनवर्ट करने के बारे में पता है, लेकिन मुझे अभी भी यह नहीं दिख रहा है कि यह संभवतः कैसे काम कर सकता है यदि 'वर्तमान' और 'अपेक्षित' बिटवाई-अलग-अलग प्रतिनिधित्व हैं (जैसा कि प्रति 'ऑपरेटर ==') मूल्य। – vpozdyayev

+0

प्रश्न के लिए कोड नमूना जोड़ा गया। – vpozdyayev