धागे इंतजार कर के एक खाली लिंक्ड सूची के साथ शुरू। सिर 0
वेटर्स की सूची के सिर पर धागा डालने के लिए सीएएस, तुलना और स्वैप का उपयोग करें। यदि सिर = -1, तो सम्मिलित या प्रतीक्षा न करें। यदि आप सही करते हैं तो आप एक लिंक्ड सूची के शीर्ष पर आइटम डालने के लिए सुरक्षित रूप से सीएएस का उपयोग कर सकते हैं।
डालने के बाद, प्रतीक्षा थ्रेड SIGUSR1 पर प्रतीक्षा करनी चाहिए। ऐसा करने के लिए sigwait() का प्रयोग करें।
तैयार होने पर, सिग्नलिंग थ्रेड प्रतीक्षा सूची के सिर को -1 तक सेट करने के लिए सीएएस का उपयोग करता है। यह किसी और धागे को प्रतीक्षा सूची में जोड़ने से रोकता है। फिर सिग्नलिंग थ्रेड प्रतीक्षा सूची में धागे को पुन: सक्रिय करता है और प्रत्येक प्रतीक्षा धागे को जागने के लिए pthread_kill (& थ्रेड, SIGUSR1) को कॉल करता है।
अगर SIGUSR1 को कॉल करने से पहले भेजा जाता है, तो सिगवाइट तुरंत वापस आ जाएगा। इस प्रकार, प्रतीक्षा सूची में थ्रेड जोड़ने और सिग्वाइट को कॉल करने के बीच कोई दौड़ नहीं होगी।
संपादित करें:
क्यों कैस तेजी से एक म्युटेक्स से है? लेमेन का जवाब (मैं एक आम आदमी हूं)। कुछ स्थितियों में कुछ चीजों के लिए यह तेज़ है, क्योंकि कोई दौड़ नहीं होने पर इसका निचला ओवरहेड होता है। इसलिए यदि आप अपनी समवर्ती समस्या को कम कर सकते हैं तो 8-16-32-64-128 संगत स्मृति के बिट्स को बदलने की आवश्यकता है, और एक दौड़ अक्सर नहीं होने वाली है, सीएएस जीतता है। सीएएस मूल रूप से थोड़ा अधिक फैंसी/महंगा मूव निर्देश है जहां आप नियमित रूप से "mov" करने जा रहे थे। यह एक "ताला exchng" या ऐसा कुछ है।
दूसरी ओर एक म्यूटेक्स अतिरिक्त सामान का एक पूरा समूह है, जो अन्य कैश लाइनों को गंदे बनाता है और अधिक मेमोरी बाधाओं का उपयोग करता है, आदि। हालांकि सीएएस x86, x64, आदि पर मेमोरी बाधा के रूप में कार्य करता है। फिर निश्चित रूप से आपको म्यूटेक्स को अनलॉक करना होगा जो शायद अतिरिक्त सामान की एक ही राशि के बारे में है।
while (1)
{
pOldHead = pHead; <-- snapshot of the world. Start of the race.
pItem->pNext = pHead;
if (CAS(&pHead, pOldHead, pItem)) <-- end of the race if phead still is pOldHead
break; // success
}
तो तुम कितनी बार लगता है कि आपके कोड सटीक एक ही समय में है कि कैस लाइन पर एक से अधिक थ्रेड के लिए जा रहा है है:
तरीका यहां बताया गया कैस का उपयोग कर एक लिंक्ड सूची में कोई आइटम जोड़ने है? हकीकत में .... अक्सर नहीं। हमने परीक्षण किया है कि एक ही समय में कई धागे के साथ लाखों आइटम जोड़ना पसंद किया है और यह 1% से कम समय से कम होता है। एक असली कार्यक्रम में, यह कभी नहीं हो सकता है।
जाहिर है कि यदि कोई दौड़ है तो आपको वापस जाना होगा और उस लूप को दोबारा करना होगा, लेकिन एक लिंक्ड सूची के मामले में, आपको इसकी क्या कीमत है?
नकारात्मकता यह है कि आप उस लिंक की गई सूची में बहुत जटिल चीजें नहीं कर सकते हैं यदि आप सिर पर आइटम जोड़ने के लिए उस विधि का उपयोग करने जा रहे हैं। एक डबल लिंक्ड सूची को लागू करने का प्रयास करें। क्या मुसीबत है।
संपादित करें:
कोड ऊपर मैं एक मैक्रो कैस का उपयोग करें। यदि आप linux का उपयोग कर रहे हैं, तो CAS = मैक्रो __sync_bool_compare_and_swap का उपयोग कर। gcc atomic builtins देखें। यदि आप इंटरलॉक कॉम्पैयर एक्सचेंज जैसे कुछ का उपयोग कर विंडोज़, सीएएस = मैक्रो का उपयोग कर रहे हैं।
inline bool CAS(volatile WORD* p, const WORD nOld, const WORD nNew) {
return InterlockedCompareExchange16((short*)p, nNew, nOld) == nOld;
}
inline bool CAS(volatile DWORD* p, const DWORD nOld, const DWORD nNew) {
return InterlockedCompareExchange((long*)p, nNew, nOld) == nOld;
}
inline bool CAS(volatile QWORD* p, const QWORD nOld, const QWORD nNew) {
return InterlockedCompareExchange64((LONGLONG*)p, nNew, nOld) == nOld;
}
inline bool CAS(void*volatile* p, const void* pOld, const void* pNew) {
return InterlockedCompareExchangePointer(p, (PVOID)pNew, (PVOID)pOld) == pOld;
}
आपका जबकि (! Globalflag) एक स्पिन ताला के बराबर है। लेकिन मुझे डर है कि मैं इस सवाल को समझ नहीं पा रहा हूं। यदि आप सिग्नल का उपयोग करते हैं, तो मैं क्या करूँगा, फिर भी आप सैमफोर या म्यूटेक्स (सिस्टम द्वारा छुपाए गए यद्यपि) के एक रूप का उपयोग करते हैं। सिग्नल पर इंतजार किए बिना, आपके पास स्पिनलॉक होगा। ग्लोबफ्लैग का उपयोग करना अच्छा होता है यदि आप प्रतीक्षा करते समय काम कर सकते हैं और ध्वज सत्य होने के बाद किसी भिन्न कार्य (या अतिरिक्त कार्य) पर स्विच कर सकते हैं। –
आपके पास जो कुछ है, उसके अलावा आपको शायद ग्लोबफ्लैग को अस्थिर के रूप में घोषित करना होगा ताकि यह सुनिश्चित किया जा सके कि संकलक वास्तव में कोड को देखने के बजाय स्मृति को पढ़ता है और निर्णय लेता है कि यह मूल्य बदल नहीं सकता है। और यह सुनिश्चित करने के लिए किसी प्रकार की मेमोरी बाधा का उपयोग करें कि एक थ्रेड द्वारा लिखे गए मान दूसरे में दिखाई दे रहे हैं, – jcoder