सभी थ्रेड के निष्पादन को बाधित करने के लिए एक थ्रेड के लिए CUDA (या NVIDIA GPUs पर) में कोई रास्ता नहीं है। जैसे ही परिणाम मिलते हैं, आप कर्नेल के तुरंत बाहर नहीं निकल सकते हैं, आज भी यह संभव नहीं है।
लेकिन एक थ्रेड परिणाम मिलने के बाद आप जितनी जल्दी हो सके से बाहर निकल सकते हैं। यहां एक मॉडल है कि आप यह कैसे करेंगे।
__global___ void kernel(volatile bool *found, ...)
{
while (!(*found) && workLeftToDo()) {
bool iFoundIt = do_some_work(...); // see notes below
if (iFoundIt) *found = true;
}
}
इस पर कुछ नोट्स।
volatile
के उपयोग पर ध्यान दें। यह महत्वपूर्ण है।
- सुनिश्चित करें कि आप
found
— प्रारंभ करें जो कि कर्नेल लॉन्च करने से पहले डिवाइस सूचक — से false
होना चाहिए!
- धागे तुरन्त बाहर निकलने नहीं होगा जब एक और धागा अपडेट
found
। वे अगली बार जब वे लूप के शीर्ष पर वापस आ जाएंगे तो वे बाहर निकलेंगे।
- आप
do_some_work
मामलों को कैसे कार्यान्वित करते हैं। यदि यह बहुत अधिक काम (या बहुत परिवर्तनीय) है, तो परिणाम मिलने के बाद बाहर निकलने में देरी लंबी (या परिवर्तनीय) होगी।यदि यह बहुत कम काम है, तो आपके थ्रेड अपने काम का अधिकतर समय उपयोगी काम करने के बजाय found
की जांच करेंगे।
do_some_work
कार्य आवंटित करने के लिए भी जिम्मेदार है (यानी कंप्यूटिंग/सूचकांक में वृद्धि), और आप यह कैसे करते हैं, यह समस्या विशिष्ट है।
- यदि आपके द्वारा लॉन्च किए गए ब्लॉक की संख्या मौजूदा जीपीयू पर कर्नेल की अधिकतम अधिभोग से काफी बड़ी है, और थ्रेड ब्लॉक के पहले चल रहे "लहर" में कोई मिलान नहीं मिलता है, तो यह कर्नेल (और नीचे दिया गया एक) डेडलॉक कर सकते हैं। यदि पहली लहर में एक मैच मिलता है, तो बाद के ब्लॉक केवल
found == true
के बाद चलेंगे, जिसका अर्थ है कि वे लॉन्च करेंगे, फिर तुरंत बाहर निकलें। समाधान केवल एक ही ब्लॉक को लॉन्च करना है जैसे कि निवासी एक साथ हो सकता है (उर्फ "अधिकतम लॉन्च"), और तदनुसार अपने कार्य आवंटन को अपडेट करें।
- यदि कार्यों की संख्या अपेक्षाकृत छोटी है, तो आप
while
को if
के साथ प्रतिस्थापित कर सकते हैं और कार्यों की संख्या को कवर करने के लिए पर्याप्त थ्रेड चला सकते हैं। फिर डेडलॉक के लिए कोई मौका नहीं है (लेकिन पिछले बिंदु का पहला भाग लागू होता है)।
workLeftToDo()
समस्या-विशिष्ट है, लेकिन ऐसा करने के लिए कोई काम नहीं होने पर यह झूठ वापस आ जाएगा, ताकि हम पर कोई मेल नहीं खा सकें कोई मिलान नहीं मिला है।
अब, उपर्युक्त परिणामस्वरूप अत्यधिक विभाजन कैंपिंग (उसी धागे पर टक्कर लगी सभी धागे) हो सकती है, खासकर एल 1 कैश के बिना पुराने आर्किटेक्चर पर। इसलिए आप प्रति ब्लॉक साझा स्थिति का उपयोग करके थोड़ा और जटिल संस्करण लिखना चाहेंगे।
__global___ void kernel(volatile bool *found, ...)
{
volatile __shared__ bool someoneFoundIt;
// initialize shared status
if (threadIdx.x == 0) someoneFoundIt = *found;
__syncthreads();
while(!someoneFoundIt && workLeftToDo()) {
bool iFoundIt = do_some_work(...);
// if I found it, tell everyone they can exit
if (iFoundIt) { someoneFoundIt = true; *found = true; }
// if someone in another block found it, tell
// everyone in my block they can exit
if (threadIdx.x == 0 && *found) someoneFoundIt = true;
__syncthreads();
}
}
इस तरह, ब्लॉक चुनावों प्रति एक धागा वैश्विक चर, और केवल धागे कि एक मैच कभी यह करने के बारे में लगता है, इसलिए वैश्विक स्मृति यातायात कम से कम है।
इसके अलावा: __global__ फ़ंक्शंस शून्य हैं क्योंकि यह परिभाषित करना मुश्किल है कि धागे के 1000s से एकल CPU थ्रेड में मूल्य कैसे वापस लाया जाए। उपयोगकर्ता के लिए डिवाइस में रिटर्न सरणी या शून्य-प्रतिलिपि मेमोरी का विरोध करने के लिए यह छोटा है जो उसके उद्देश्य के अनुरूप है, लेकिन सामान्य तंत्र बनाना मुश्किल है।
अस्वीकरण: ब्राउज़र में लिखा कोड, अवांछित, असत्यापित।
यहाँ एक sulution है कि मैं प्राप्त है, लेकिन मैं अभी भी रूप में यह सही स्ट्रिंग मिला वैश्विक समारोह के रूप में जल्द ही जवाब दे सकते हैं चाहते हैं ... उद्धरण आप संवाद करने के लिए CTAs भीतर एक पदानुक्रमित साझा स्मृति झंडा और एक वैश्विक स्मृति ध्वज का उपयोग कर सकते सभी सीटीए में और इन दोनों को अस्थिर होना चाहिए। सभी धागे/सीटीए समय-समय पर इन झंडे को जांचने के लिए जांचते हैं कि क्या खोज जारी रखना है (वह जो स्ट्रिंग को अद्यतन करता है)। QUOTE –