2010-10-19 24 views
21

मैं सीखने की कोशिश कर रहा हूं कि rand_r का उपयोग कैसे करें, और this question पढ़ने के बाद भी मैं थोड़ा उलझन में हूं, क्या कोई कृपया एक नज़र डालें और बताएं कि मैं क्या खो रहा हूं? मेरी समझ के लिए, rand_r कुछ मूल्य (या कुछ प्रारंभिक मान के साथ स्मृति का एक टुकड़ा) के लिए एक सूचक लेता है और हर बार इसे कॉल करने के लिए नई संख्या उत्पन्न करने के लिए इसका उपयोग करता है। प्रत्येक थ्रेड जो rand_r को कॉल करता है उसे विभिन्न थ्रेड के बीच "वास्तविक यादृच्छिक" संख्या प्राप्त करने के लिए एक अद्वितीय सूचक (या स्मृति का टुकड़ा) प्रदान करना चाहिए। यही कारण है कि:मैं rand_r का उपयोग कैसे करूं और मैं थ्रेड सुरक्षित तरीके से इसका उपयोग कैसे करूं?

int globalSeed; 

//thread 1 
rand_r(&globalSeed); 

//thread 2 
rand_r(&globalSeed); 

इसका उपयोग करने का गलत तरीका है। अगर मेरे पास

int seed1,seed2; 

//thread 1 
rand_r(&seed1); 

//thread 2 
rand_r(&seed2); 

धागे के बीच "वास्तविक यादृच्छिक" संख्याएं उत्पन्न करने का यह सही तरीका होगा?


संपादित करें:

  1. अगर धागा 1 में मैं एन 1 के बीच एक यादृच्छिक संख्या की जरूरत है, मैं (rand_r(&seed1) % (n-1)) + 1 करना चाहिए: ऊपर भाग के जवाब को पढ़ने के बाद अतिरिक्त प्रश्न? या ऐसा करने का दूसरा आम तरीका है?
  2. क्या बीज के लिए स्मृति गतिशील रूप से आवंटित होने पर यह सही या सामान्य है?

उत्तर

15

यह सही है। पहले मामले में आप क्या कर रहे हैं rand_r की थ्रेड-सुरक्षा प्रकृति को छोड़कर। कई गैर-थ्रेड-सुरक्षित कार्यों के साथ, उस स्थिति में कॉल के बीच लगातार स्थिति संग्रहीत होती है (जैसे यादृच्छिक बीज)।

थ्रेड-सुरक्षित संस्करण के साथ, आप वास्तव में डेटा के थ्रेड-विशिष्ट टुकड़े (seed1 और seed2) प्रदान करते हैं ताकि यह सुनिश्चित किया जा सके कि राज्य धागे के बीच साझा नहीं किया गया है।

ध्यान रखें कि यह संख्याओं को वास्तव में यादृच्छिक नहीं बनाता है, यह सिर्फ एक दूसरे से स्वतंत्र अनुक्रम बनाता है। यदि आप उन्हें एक ही बीज के साथ शुरू करते हैं, तो आप शायद दोनों धागे में एक ही अनुक्रम प्राप्त करेंगे।

उदाहरण के तौर पर, मान लीजिए कि आपको एक यादृच्छिक अनुक्रम 2, 3, 5, 7, 11, 13, 17 प्राप्त होता है जो 0 के आरंभिक बीज को दिया जाता है। साझा बीज के साथ, rand_r पर दो अलग-अलग धागे से वैकल्पिक कॉल इस कारण:

thread 1    thread 2 
      <--- 2 
       3 ---> 
      <--- 5 
       7 ---> 
      <--- 11 
       13 ---> 
      <--- 17 

और उस सबसे अच्छा मामला है - आप वास्तव में लग सकता है कि साझा राज्य दूषित हो जाता है, क्योंकि यह के बारे में अपडेट परमाणु नहीं हो सकता।

thread 1    thread 2 
      <--- 2a 
       2b ---> 
      <--- 3a 
       3b ---> 
      <--- 5a 
       5b ---> 
       :: 

कुछ धागे की सुरक्षित कॉल इस तरह धागे की विशिष्ट राज्य प्रदान करने के लिए आप की आवश्यकता होती है, दूसरों:

गैर साझा राज्य ( a और b यादृच्छिक संख्या के दो अलग-अलग स्रोतों का प्रतिनिधित्व करने के साथ) के साथ

कवर के तहत थ्रेड-विशिष्ट डेटा बना सकते हैं (थ्रेड आईडी या इसी तरह की जानकारी का उपयोग करके) ताकि आपको इसके बारे में चिंता करने की आवश्यकता न हो, और आप थ्रेडेड और गैर-थ्रेडेड वातावरण में बिल्कुल उसी स्रोत कोड का उपयोग कर सकें। मैं बाद वाले को पसंद करता हूं, क्योंकि यह मेरी जिंदगी को आसान बनाता है।


संपादित प्रश्न के लिए अतिरिक्त सामान:

> If in thread 1, I need a random number between 1 to n, should I do '(rand_r(&seed1) % (n-1)) + 1', or there is other common way of doing this?

मान लिया जाये कि आप 1 और nसमावेशी के बीच कोई मान चाहते हैं, (rand_r(&seed1) % n) + 1 का उपयोग करें। पहला बिट आपको 0 से n-1 समेत एक मान देता है, फिर आप वांछित सीमा प्राप्त करने के लिए 1 जोड़ते हैं।

> Is it right or normal if the memory for the seed is dynamically allocated?

बीज के रूप में आप इसे प्रयोग कर रहे हैं जब तक लगातार हो गया है। आप इसे गतिशील रूप से थ्रेड में आवंटित कर सकते हैं लेकिन आप इसे थ्रेड के शीर्ष-स्तरीय फ़ंक्शन में भी घोषित कर सकते हैं। उन दोनों मामलों में, आपको किसी भी तरह के निचले स्तर पर पते को संवाद करने की आवश्यकता होगी (जब तक कि आपका धागा केवल एक ऐसा कार्य न हो जो असंभव है)।

आप या तो इसे फ़ंक्शन कॉल के माध्यम से पास कर सकते हैं या किसी वैश्विक सरणी को सेट कर सकते हैं जहां निचले स्तर सही बीज पते की खोज कर सकते हैं।

वैकल्पिक रूप से, चूंकि आपको वैश्विक सरणी की आवश्यकता है, इसलिए आपके पास बीज पते की बजाय बीज की वैश्विक सरणी हो सकती है, जो निम्न स्तर उनके बीज को खोजने के लिए उपयोग कर सकते हैं।

आप शायद (वैश्विक सरणी का उपयोग करने के दोनों मामलों में) की एक महत्वपूर्ण संरचना है जिसमें थ्रेड आईडी को एक कुंजी और उपयोग करने के लिए बीज शामिल है। इसके बाद आपको अपने अपनेrand() दिनचर्या लिखनी होगी जो सही बीज स्थित है और इसके साथ rand_r() कहा जाता है।

यह यही कारण है कि मैं लाइब्रेरी दिनचर्या पसंद करता हूं जो थ्रेड-विशिष्ट डेटा के साथ कवर के तहत ऐसा करता है।

+0

धन्यवाद !! तो सबसे अच्छा तरीका अलग-अलग धागे के लिए अलग-अलग शुरुआती मूल्यों के साथ हमेशा अलग-अलग बीज का उपयोग कर रहा है, है ना? – derrdji

+0

मैं आमतौर पर कहूंगा, हाँ। लेकिन ऐसी कुछ स्थितियां हैं जहां आप _want_ साझा स्थिति (मेरे उत्तर में पहला आरेख) कर सकते हैं, इस मामले में आप _same_ राज्य के साथ 'rand_r' को कॉल करके भ्रष्टाचार की संभावना से बच सकते हैं लेकिन म्यूटेक्स द्वारा संरक्षित हैं। एक चीज जिसे आप नहीं करना चाहते हैं, दोनों अनुक्रमों को उसी बीज के साथ शुरू करना है क्योंकि अनुक्रम तब समान होंगे। – paxdiablo

+0

हाँ, धन्यवाद !! मैं बस यह पूछने वाला था कि क्या मैं एक साझा कर सकता हूं और mutex लॉक के साथ rand_r कॉल को सुरक्षित रख सकता हूं। – derrdji

संबंधित मुद्दे