2016-10-31 8 views
5

आमतौर पर, यूआई थ्रेड में या एएसपी.NET संदर्भ के साथ एक एसिंक डेडलॉक होता है। मैं एक कंसोल एप्लिकेशन में डेडलॉक अनुकरण करने की कोशिश कर रहा हूं ताकि मैं अपने लाइब्रेरी कोडों का परीक्षण कर सकूं।कंसोल एप्लिकेशन में एसिंक डेडलॉक अनुकरण करें

class Program 
{ 
    private static async Task DelayAsync() 
    { 
     Console.WriteLine("DelayAsync.Start"); 
     await Task.Delay(1000); 
     Console.WriteLine("DelayAsync.End"); 
    } 

    // This method causes a deadlock when called in a GUI or ASP.NET context. 
    public static void Deadlock() 
    { 
     Console.WriteLine("Deadlock.Start"); 
     // Start the delay. 
     var delayTask = DelayAsync(); 
     // Wait for the delay to complete. 
     delayTask.Wait(); 
     Console.WriteLine("Deadlock.End"); 
    } 

    static void Main(string[] args) 
    { 
     var thread = new Thread(() => 
     { 
      Console.WriteLine("Thread.Start"); 
      SynchronizationContext.SetSynchronizationContext(new DedicatedThreadSynchronisationContext()); 
      Deadlock(); 
      Console.WriteLine("Thread.End"); 
     }); 
     thread.Start(); 
     Console.WriteLine("Thread.Join.Start"); 
     thread.Join(); 
     Console.WriteLine("Thread.Join.End"); 
     Console.WriteLine("Press any key to exit"); 
     Console.ReadKey(true); 
     Console.WriteLine("Pressed"); 
    } 
} 

तो डेडलॉक() एक सही संदर्भ में एक गतिरोध का कारण होना चाहिए:

तो यहाँ मेरी प्रयास है। ASP.NET संदर्भ अनुकरण करने के लिए, मैं DedicatedThreadSynchronisationContexthttps://stackoverflow.com/a/31714115/121240 से उपयोग कर रहा हूँ:

public sealed class DedicatedThreadSynchronisationContext : SynchronizationContext, IDisposable 
{ 
    public DedicatedThreadSynchronisationContext() 
    { 
     m_thread = new Thread(ThreadWorkerDelegate); 
     m_thread.Start(this); 
    } 

    public void Dispose() 
    { 
     m_queue.CompleteAdding(); 
    } 

    /// <summary>Dispatches an asynchronous message to the synchronization context.</summary> 
    /// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param> 
    /// <param name="state">The object passed to the delegate.</param> 
    public override void Post(SendOrPostCallback d, object state) 
    { 
     if (d == null) throw new ArgumentNullException("d"); 
     m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state)); 
    } 

    /// <summary> As 
    public override void Send(SendOrPostCallback d, object state) 
    { 
     using (var handledEvent = new ManualResetEvent(false)) 
     { 
      Post(SendOrPostCallback_BlockingWrapper, Tuple.Create(d, state, handledEvent)); 
      handledEvent.WaitOne(); 
     } 
    } 

    public int WorkerThreadId { get { return m_thread.ManagedThreadId; } } 
    //========================================================================================= 

    private static void SendOrPostCallback_BlockingWrapper(object state) 
    { 
     var innerCallback = (state as Tuple<SendOrPostCallback, object, ManualResetEvent>); 
     try 
     { 
      innerCallback.Item1(innerCallback.Item2); 
     } 
     finally 
     { 
      innerCallback.Item3.Set(); 
     } 
    } 

    /// <summary>The queue of work items.</summary> 
    private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue = 
     new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); 

    private readonly Thread m_thread = null; 

    /// <summary>Runs an loop to process all queued work items.</summary> 
    private void ThreadWorkerDelegate(object obj) 
    { 
     SynchronizationContext.SetSynchronizationContext(obj as SynchronizationContext); 

     try 
     { 
      foreach (var workItem in m_queue.GetConsumingEnumerable()) 
       workItem.Key(workItem.Value); 
     } 
     catch (ObjectDisposedException) { } 
    } 
} 

मैं डेडलॉक() कॉल करने से पहले संदर्भ सेट:

SynchronizationContext.SetSynchronizationContext(new DedicatedThreadSynchronisationContext()); 

मैं कोड पर लटका करने की उम्मीद यह लाइन क्योंकि इसे संदर्भ को कैप्चर करना चाहिए:

await Task.Delay(1000); 

हालांकि, यह ठीक है डी कार्यक्रम अंत के माध्यम से चलाता है, और यह "दबाया" प्रिंट करता है। (हालांकि प्रोग्राम समर्पित थ्रेड सिंक्रनाइज़ेशन कॉन्टेक्स्ट पर है। थ्रेड वर्कर्सडिलेगेट() इसलिए यह अस्तित्व में नहीं है, लेकिन मैं इसे एक मामूली समस्या मानता हूं।)

यह मृत लॉक क्यों नहीं बनाता है? मृत लॉक अनुकरण करने का सही तरीका क्या है?

========================================

संपादित

Luaan द्वारा जवाब के अनुसार,

मैं DedicatedThreadSynchronisationContext.Send (प्रयुक्त) के बजाय एक नया धागा बनाने का: संदर्भ अंतर्गत चलाने के लिए

 Console.WriteLine("Send.Start"); 
     var staContext = new DedicatedThreadSynchronisationContext(); 
     staContext.Send((state) => 
     { 
      Deadlock(); 
     }, null); 
     Console.WriteLine("Send.End"); 

यह डेडलॉक की सुविधा देता है(), तो 'का इंतजार' एक ही संदर्भ को कैप्चर करता है इस प्रकार एक मृत ताला होता है।

धन्यवाद लुआन!

उत्तर

3

क्योंकि Deadlock आपके सिंक्रनाइज़ेशन संदर्भ के समान थ्रेड पर नहीं चलता है।

आपको सिंक्रनाइज़ेशन संदर्भ पर Deadlock चलाने की ज़रूरत है - बस संदर्भ सेट करना और विधि को कॉल करना यह सुनिश्चित नहीं करता है।

SynchronizationContext.Current.Send(_ => Deadlock(), null); 

यह आपको देरी कार्य इंतजार :)

+0

यह समझ में आता है पर एक अच्छी गतिरोध देता है:

छोटे संशोधन के साथ ऐसा करने का सबसे आसान तरीका तुल्यकालन संदर्भ के लिए तुल्यकालिक Deadlock भेजने के लिए है । मैंने डेडिकेटेड थ्रेड सिंक्रनाइज़ेशन कॉन्टेक्स्ट पर भेजें() को बुलाया, और वॉयला, एक मृत लॉक! – wooohoh

0

सिंक्रनाइज़ेशन संदर्भ जो आप उपयोग कर रहे हैं वह एक नया धागा बना रहा है और उस काम को उस थ्रेड पर भेजा गया है, इसलिए तथ्य यह है कि आप थ्रेड को अवरुद्ध कर रहे हैं जिसे आपने सिंक्रनाइज़ेशन संदर्भ सेट अप किया है अप्रासंगिक है क्योंकि यह धागा नहीं है जो काम कर रहा है।

आप इसे गतिरोध करना चाहता है तो आपको लगता है कि तुल्यकालन संदर्भ का उपयोग करने के लिए और फिर वहाँ ब्लॉक, जब वहाँ भी इसे जारी रखने के लिए आवश्यक अतिरिक्त कॉलबैक हैं एक कॉलबैक शेड्यूल करने के लिए आवश्यकता होगी। वैकल्पिक रूप से, आप एक और पारंपरिक संदेश लूप का उपयोग कर सकते हैं जो थ्रेड में चलता है जो इसे शुरू करता है, बजाय एक नया चुपचाप बनाने के बजाए।

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