2013-02-28 19 views
14

Uygulamamın eklentileri ayrı uygulama etki alanlarına yüklemesi ve ardından bunların içeriklerini eşzamansız bir şekilde yürütmesi gerekiyor.Uygulama etki alanı uzaklaştırma ve görevlerini birleştirirken kilitlenme

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; 
     } 
    } 
} 

Sanki kullanılır: Ben marshallable türlerinde Task sarmak için bazı kodlar yazdım

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; 
     }); 
    } 
} 

Ama bir engelle çalıştırmak. ClientComplete'da bakarsanız, eklediğim bir Task.Yield() var. Bu satırı yorumluyorum, ClientComplete asla geri dönmeyecek. Herhangi bir fikir?

+2

http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code gibi "C# async deadlock ConfigureAwait" için arama sonuçlarını göz önünde bulundurun bir çözüm olurdu. –

+0

Bunu tekrarlayamıyorum. 'ControllerAppDomain.SomethingAsync' hiçbir zaman benim için askıda kalıyor ya da ister bir thread havuz bağlamında isterse tek iş parçacıklı bir bağlamda olsun 'bekle' özelliğini kullanmam. Yukarıdaki kodun sorunu kopyaladığından emin misiniz? –

+0

@StephenCleary Kodu başka bir makinede denedim ve orada da üretemiyorum. İlginç. –

cevap

2

En iyi tahminle nedeniyle bekliyor içeren zaman uyumsuz yönteminin bu konularda karşı karşıya ve bu, bazı geri dönüşümlü Konu tahsis hangi ThreadPool'da aracılığıyla yönetilen olmasıdır.

Referans Best practice to call ConfigureAwait for all server-side code

Aslında sadece bunu yapabilir ekibimizden (farklı bir iş parçacığı üzerine koymak) yapıyor. Async yönteminiz numarasına ulaştıktan sonra, yöntem engellenir ancak iş parçacığı iş parçacığına döner. Yöntem devam etmeye hazır olduğunda, herhangi bir iş parçacığı, iş parçacığı havuzundan kapılır ve yönteme devam etmek için kullanılır.

deneyin, kodunuzu düzenlemeye bazal durumlar için konuları üretmek ve performans sonuncusu için.

+0

Bu cevaptan kime düşse, nedenini açıklayan bir yorum bırakmak yararlı olacaktır. –

İlgili konular