2017-12-20 104 views
5

मुझे मेरा कोड के टुकड़े में डेडलॉक-इश्यू का सामना करना पड़ रहा है। शुक्र है, मैं नीचे दिए गए उदाहरण में समस्या को पुन: उत्पन्न करने में सक्षम हूं। एक सामान्य .NET कोर 2.0 कंसोल अनुप्रयोग के रूप में चलाएं।क्या डेडलॉक का कारण बन रहा है?

class Class2 
{ 

    static void Main(string[] args) 
    { 
     Task.Run(MainAsync); 
     Console.WriteLine("Press any key..."); 
     Console.ReadKey(); 
    } 

    static async Task MainAsync() 
    { 
     await StartAsync(); 
     //await Task.Delay(1); //a little delay makes it working 
     Stop(); 
    } 


    static async Task StartAsync() 
    { 
     var tcs = new TaskCompletionSource<object>(); 
     StartCore(tcs); 
     await tcs.Task; 
    } 


    static void StartCore(TaskCompletionSource<object> tcs) 
    { 
     _cts = new CancellationTokenSource(); 
     _thread = new Thread(Worker); 
     _thread.Start(tcs); 
    } 


    static Thread _thread; 
    static CancellationTokenSource _cts; 


    static void Worker(object state) 
    { 
     Console.WriteLine("entering worker"); 
     Thread.Sleep(100); //some work 

     var tcs = (TaskCompletionSource<object>)state; 
     tcs.SetResult(null); 

     Console.WriteLine("entering loop"); 
     while (_cts.IsCancellationRequested == false) 
     { 
      Thread.Sleep(100); //some work 
     } 
     Console.WriteLine("exiting worker"); 
    } 


    static void Stop() 
    { 
     Console.WriteLine("entering stop"); 
     _cts.Cancel(); 
     _thread.Join(); 
     Console.WriteLine("exiting stop"); 
    } 

} 

मैं क्या उम्मीद थी पूरा अनुक्रम इस प्रकार है:

Press any key... 
entering worker 
entering loop 
entering stop 
exiting worker 
exiting stop 

हालांकि, वास्तविक अनुक्रम Thread.Join फोन पर रुक जाता:

Press any key... 
entering worker 
entering stop 

अंत में, अगर मैं एक डालने MainAsync शरीर में छोटी देरी, सब ठीक हो जाता है। क्यों (कहाँ) डेडलॉक होता है?

नोट: मूल कोड में मैंने के बजाय SemaphoreSlim का उपयोग करके हल किया, और इसमें कोई समस्या नहीं है। मैं केवल यह समझना चाहता हूं कि समस्या कहां है।

+1

कोई कारण है कि आप 'थ्रेड' के साथ 'कार्य' को मिला रहे हैं? – Groo

+0

'var tcs = new taskCompletionSource (टास्क क्रिएशनऑप्शन .RunContinuationsAsynchronously) में बदलें;' और यह आपकी अपेक्षा के अनुसार चलाएगा। अब 'SetResult' निरंतर निरंतर चलता है, और निरंतरता में' रोकें) 'पर कॉल शामिल है, जो स्वयं थ्रेड में शामिल होता है जिसमें' SetResult' निष्पादित किया गया था, इसलिए वे डेडलॉक करते हैं। – Evk

+0

@ मूल कोड में ग्रूओ एक लंबे समय से चलने वाला धागा (कार्यकर्ता) है जो मिश्रण कार्यों के बिना कई नौकरियां करता है। हालांकि, कार्यकर्ता/थ्रेड शुरू करने के लिए खुलासा करने वाला एक प्रतीक्षा योग्य कार्य है जो कुछ शुरुआती नौकरी के दौरान पूरा हो जाता है। –

उत्तर

3

tcs.SetResult(null);Worker() में कॉल अंतर्निहित कार्य समाप्त होने तक वापस नहीं आएगा (विवरण के लिए this question देखें)। आप कार्य की स्थिति के मामले में WaitingForActivation है यही कारण है कि आप एक गतिरोध मिलती है:

  1. थ्रेड क्रियान्वित Worker()tcs.SetResult(null) कॉल द्वारा अवरुद्ध है।

  2. Stop() निष्पादित थ्रेड _thread.Join() कॉल द्वारा अवरुद्ध है।

+0

मदद के लिए धन्यवाद! –

0

क्योंकि MainAsync() धागा अन्य धागे की तुलना में 'तेज' है। और आप केवल धागे पर कार्यों पर नियंत्रण कर रहे हैं!

आपकी विधि में MainAsync() आप अपना काम पूरा करने के लिए विधि StartAsync() का इंतजार कर रहे हैं और फिर आप धागा शुरू करते हैं। एक बार विधि StartAsync() अपने काम (बनाया और प्रारंभ धागा) के साथ किया जाता है जो कार्य अपने काम को खत्म करने के बारे में MainAsync() सूचित करता है। फिर MainAsync() कॉल रोकें विधि। लेकिन आपका धागा कहां है? यह बिना किसी नियंत्रण के समानांतर में चलता है और अपना काम पूरा करने की कोशिश करता है। यह डेडलॉक नहीं है, कार्य और धागे के बीच कोई सिंक्रनाइज़ेशन नहीं है।

Thats क्यों आप await Task.Delay(1) डालते हैं तो आपका कोड काम करता है क्योंकि कार्य समाप्त होने से पहले काम खत्म करने के लिए थ्रेड पर्याप्त तेज़ है (thread.join)।

+0

हम्म .... पहले बंद करें, StartAsync समाप्त होता है जब TaskCompletionSource SetResult विधि द्वारा जारी किया जाएगा, और यह थ्रेड के अंदर है। दूसरा, धागा तब तक समाप्त नहीं होना चाहिए जब तक कि टोकन रद्द नहीं किया जाएगा (और यह स्टॉप विधि में है)। –

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