2013-02-28 5 views
14

मेरे ऐप को अलग-अलग ऐप डोमेन में प्लगइन लोड करने की आवश्यकता है और फिर उनमें से कुछ कोड को अतुल्यकालिक रूप से निष्पादित करने की आवश्यकता है।ऐप डोमेन रीमोटिंग और कार्यों को जोड़ते समय डेडलॉक

static class RemoteTask 
{ 
    public static async Task<T> ClientComplete<T>(RemoteTask<T> remoteTask, 
                CancellationToken cancellationToken) 
    { 
     T result; 

     using (cancellationToken.Register(remoteTask.Cancel)) 
     { 
      RemoteTaskCompletionSource<T> tcs = new RemoteTaskCompletionSource<T>(); 
      remoteTask.Complete(tcs); 
      result = await tcs.Task; 
     } 

     await Task.Yield(); // HACK!! 

     return result; 
    } 

    public static RemoteTask<T> ServerStart<T>(Func<CancellationToken, Task<T>> func) 
    { 
     return new RemoteTask<T>(func); 
    } 
} 

class RemoteTask<T> : MarshalByRefObject 
{ 
    readonly CancellationTokenSource cts = new CancellationTokenSource(); 
    readonly Task<T> task; 

    internal RemoteTask(Func<CancellationToken, Task<T>> starter) 
    { 
     this.task = starter(cts.Token); 
    } 

    internal void Complete(RemoteTaskCompletionSource<T> tcs) 
    { 
     task.ContinueWith(t => 
     { 
      if (t.IsFaulted) 
      { 
       tcs.TrySetException(t.Exception); 
      } 
      else if (t.IsCanceled) 
      { 
       tcs.TrySetCancelled(); 
      } 
      else 
      { 
       tcs.TrySetResult(t.Result); 
      } 
     }, TaskContinuationOptions.ExecuteSynchronously); 
    } 

    internal void Cancel() 
    { 
     cts.Cancel(); 
    } 
} 

class RemoteTaskCompletionSource<T> : MarshalByRefObject 
{ 
    readonly TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(); 

    public bool TrySetResult(T result) { return tcs.TrySetResult(result); } 
    public bool TrySetCancelled() { return tcs.TrySetCanceled(); } 
    public bool TrySetException(Exception ex) { return tcs.TrySetException(ex); } 

    public Task<T> Task 
    { 
     get 
     { 
      return tcs.Task; 
     } 
    } 
} 

ऐसा किया जाता है:: मैं marshallable प्रकार में Task रैप करने के लिए कुछ कोड लिखा है

sealed class ControllerAppDomain 
{ 
    PluginAppDomain plugin; 

    public Task<int> SomethingAsync() 
    { 
     return RemoteTask.ClientComplete(plugin.SomethingAsync(), CancellationToken.None); 
    } 
} 

sealed class PluginAppDomain : MarshalByRefObject 
{ 
    public RemoteTask<int> SomethingAsync() 
    { 
     return RemoteTask.ServerStart(async cts => 
     { 
      cts.ThrowIfCancellationRequested(); 
      return 1; 
     }); 
    } 
} 

लेकिन मैं कोई समस्या आई है। यदि आप ClientComplete में देखते हैं, तो मैंने Task.Yield() डाला है। अगर मैं इस पंक्ति पर टिप्पणी करता हूं, ClientComplete कभी वापस नहीं आएगा। कोई विचार?

+2

"C# async deadlock ConfigureAwait" के लिए खोज परिणाम देखें जैसे http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code जैसा कि मुझे लगता है एक समाधान होगा। –

+0

मैं इसे दोबारा करने में सक्षम नहीं हूं। 'ControllerAppDomain.SomethingAsync' मेरे लिए कभी नहीं लटकाता है, चाहे मैं उस पर अवरुद्ध करता हूं या 'प्रतीक्षा' का उपयोग करता हूं, चाहे थ्रेड पूल संदर्भ में या एकल-थ्रेडेड संदर्भ में। क्या आप सुनिश्चित हैं कि उपरोक्त कोड समस्या को डुप्लिकेट करता है? –

+0

@ स्टीफन क्लेरी मैंने अभी किसी अन्य मशीन पर कोड की कोशिश की है और इसे वहां पुन: उत्पन्न नहीं कर सकता है। दिलचस्प। –

उत्तर

2

मेरे सबसे अच्छा अनुमान है कि आप async विधि जिसमें का इंतजार की वजह से इन मुद्दों का सामना कर रहे हैं और इस ThreadPool के माध्यम से किया जाता है जो कुछ पुनर्नवीनीकरण थ्रेड आवंटित कर सकते हैं है।

संदर्भ Best practice to call ConfigureAwait for all server-side code

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

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

+0

जो भी इस जवाब को वोट देता है, वह यह बताने में मदद करेगा कि क्यों। –

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