2012-05-24 13 views
7

पूरा करता है मैं प्रारंभ/अंत शैली विधियों का उपयोग कर कुछ एसिंक्रोनस नेटवर्क I/O कर रहा हूं। (यह वास्तव में एज़ूर टेबल स्टोरेज के खिलाफ एक प्रश्न है, लेकिन मुझे लगता है कि यह महत्वपूर्ण नहीं है।) मैंने ThreadPool.RegisterWaitForSingleObject() का उपयोग कर क्लाइंट साइड टाइमआउट लागू किया है। जहां तक ​​मैं कह सकता हूं यह ठीक काम कर रहा है।सी #: पंजीकरण WaitForSingleObject का उपयोग करते हुए यदि ऑपरेशन पहले

क्योंकि ThreadPool.RegisterWaitForSingleObject() एक तर्क के रूप में WaitHandle लेता है, मुझे I/O ऑपरेशन शुरू करना है, फिर ThreadPool.RegisterWaitForSingleObject() निष्पादित करें। ऐसा लगता है कि इस संभावना को प्रस्तुत करता है कि I/O पूरा होने से पहले मैं पूरा करता हूं।

एक सरलीकृत कोड नमूना:

private void RunQuery(QueryState queryState) 
{ 
    //Start I/O operation 
    IAsyncResult asyncResult = queryState.Query.BeginExecuteSegmented(NoopAsyncCallback, queryState); 

    //What if the I/O operation completes here? 

    queryState.TimeoutWaitHandle = ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, QuerySegmentCompleted, asyncResult, queryTimeout, true); 
} 

private void QuerySegmentCompleted(object opState, bool timedOut){ 
    IAsyncResult asyncResult = opState as IAsyncResult; 
    QueryState state = asyncResult.AsyncState as QueryState; 

    //If the I/O completed quickly, could TimeoutWaitHandle could be null here? 
    //If so, what do I do about that? 
    state.TimeoutWaitHandle.Unregister(asyncResult.AsyncWaitHandle); 
} 

इस संभाल करने के लिए उचित तरीका क्या है? क्या मुझे अभी भी Unregister() 'AsyncWaitHandle में चिंता करने की ज़रूरत है? यदि हां, तो क्या इसे सेट करने के लिए प्रतीक्षा करने का एक आसान तरीका है?

+0

क्या आपने मध्य में 'थ्रेड स्लीप' डालने का प्रयास किया है ताकि I/O ऑपरेशन को पूरा करने के लिए समय की अनुमति दी जा सके और देखें कि क्या होता है? – mellamokb

+0

मैंने नहीं किया है। मुझे लगता है कि मैंने देखा है कि यह केवल 3-4 बार होता है, और फिर केवल भारी लोड उत्पादन मशीनों पर। मैं अपने असली कोड में स्लीप() कॉल जोड़ने शुरू नहीं करना चाहूंगा। –

+0

पाठ्यक्रम के अपने विकास वातावरण में इसका परीक्षण करें। जब आप कहते हैं कि आपने देखा है कि यह केवल 3-4 बार होता है, तो आपने क्या देखा है? एक यादृच्छिक अस्पष्ट NullPointerException? – mellamokb

उत्तर

4

हाँ, आप और हर किसी को यह समस्या है। और इससे कोई फर्क नहीं पड़ता कि आईओओ सिंक्रनाइज़ हो गया है या नहीं। कॉलबैक और असाइनमेंट के बीच अभी भी एक दौड़ है। माइक्रोसॉफ्ट को उस कॉलबैक फ़ंक्शन पर स्वचालित रूप से RegisteredWaitHandle प्रदान करना चाहिए था। वह सब कुछ हल हो गया होगा। ओह ठीक है, हिंडसाइट हमेशा 20-20 है जैसा कि वे कहते हैं।

आपको क्या करना है RegisteredWaitHandle परिवर्तनीय पढ़ना जारी रखें जब तक कि यह अब शून्य न हो। यह एक तंग पाश में ऐसा करना ठीक है क्योंकि दौड़ इतनी सूक्ष्म है कि लूप कई बार कताई नहीं करेगा।

private void RunQuery(QueryState queryState) 
{ 
    // Start the operation. 
    var asyncResult = queryState.Query.BeginExecuteSegmented(NoopAsyncCallback, queryState); 

    // Register a callback. 
    RegisteredWaitHandle shared = null; 
    RegisteredWaitHandle produced = ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, 
    (state, timedout) => 
    { 
     var asyncResult = opState as IAsyncResult; 
     var state = asyncResult.AsyncState as QueryState; 
     while (true) 
     { 
     // Keep reading until the value is no longer null. 
     RegisteredWaitHandle consumed = Interlocked.CompareExchange(ref shared, null, null); 
     if (consumed != null) 
     { 
      consumed.Unregister(asyncResult.AsyncWaitHandle); 
      break; 
     } 
     } 
    }, asyncResult, queryTimeout, true); 

    // Publish the RegisteredWaitHandle so that the callback can see it. 
    Interlocked.CompareExchange(ref shared, produced, null); 
} 
+0

मुझे लगता है कि मैं देख रहा हूं कि आप यहां क्या चल रहे हैं। क्या वास्तव में दो पंजीकृत WaitHandle चर, और तुलना एक्सचेंज() होना आवश्यक है? चूंकि सूचक असाइनमेंट एक परमाणु संचालन है, क्या मैं सिर्फ कॉलबैक के अंदर 'उत्पादित' चर की जांच नहीं कर सकता? –

+0

@breischl: ठीक है, आपको मेमोरी बाधा की आवश्यकता है ताकि आपको प्रत्येक पुनरावृत्ति पर चर के "ताजा पढ़ा" मिल सके। आप शायद 'Interlocked.CompareExchange' कॉल को छोड़ने के लिए ठीक हो जाएंगे क्योंकि मुझे यकीन है कि' पंजीकृत WaitHandle.Unregistered' मेमोरी बाधा उत्पन्न करता है। लेकिन, व्यक्तिगत रूप से, मैं इस पैटर्न के साथ रहूंगा क्योंकि 'Interlocked.CompareExchange' इसे स्पष्ट करता है। –

+0

'उत्पादित' को 'अस्थिर' के रूप में घोषित नहीं करना एक ही प्रभाव है? –

1

यदि I/O टाइमआउट से पहले पूरा हो गया है तो आपको पंजीकरण रद्द करने की आवश्यकता नहीं है क्योंकि यह आपके कॉलबैक को सिग्नल करने वाला पूरा होने वाला था। वास्तव में अनियंत्रित विधि के दस्तावेज़ों को पढ़ने पर यह कॉल करने के लिए पूरी तरह से अनावश्यक लगता है क्योंकि आप केवल एक बार निष्पादित कर रहे हैं और आप एक असंबंधित विधि में पंजीकरण नहीं कर रहे हैं।

http://msdn.microsoft.com/en-us/library/system.threading.registeredwaithandle.unregister.aspx

एक कॉलबैक विधि कार्य प्रगति पर है, तो जब अपंजीकृत कार्यान्वित करता है, waitObject संकेत नहीं जब तक कॉलबैक विधि को पूरा करता है। विशेष रूप से, यदि कोई कॉलबैक विधि अनधिकृत निष्पादित करती है, तो प्रतीक्षा करें जब तक कि कॉलबैक विधि पूर्ण नहीं हो जाती है तब तक प्रतीक्षा करें।

+0

मुझे लगता है कि उद्धृत दस्तावेज कह रहा है कि यह मेरे ऑपरेशन के वेटहैंडल को संकेत नहीं देगा। ऐसा लगता है कि मैं ThreadPool से प्राप्त रजिस्ट्रार WaitHandle के बारे में कुछ भी नहीं कहता। लेकिन यह बहुत भ्रमित है, इसलिए मैं गलत हो सकता था। RegisterWaitForSingleObject() पर प्रलेखन स्पष्ट रूप से कहता है कि आपको हमेशा पंजीकरण करना चाहिए(), इसलिए मुझे लगता है कि मुझे इसे कहीं करने की आवश्यकता है। http://msdn.microsoft.com/en-us/library/w9f75h7a.aspx –

+0

@breischl क्वेरी सेगमेंट है जिसे केवल RegisterWaitForSingleObject से कॉल के रूप में बुलाया जाता है? – Slugart

+0

वर्तमान में, हाँ। –

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