2015-01-05 28 views
0

我想在工作線程的上下文中從主線程執行一個方法,但我不知道如何去做。來自主線程的Windows服務調用方法

詳細:

  1. 主要Serivce開始
  2. 工作線程開始
  3. 工作線程我想調用一個方法裏面,而不是工作者線程上下文中

燦有人給我一個提示如何執行此操作?

+0

你想在特定的線程上執行此操作還是需要任何工作線程? –

+1

請解釋爲什麼「不在工作者線程上下文中」?你的服務的主線程是什麼促使你想要在那裏執行方法而不是在工作線程中?如果你只是在工作線程中調用方法會發生什麼壞事?你的問題中缺少重要的細節,需要提供一個好的答案,並縮小問題的範圍,使其不那麼廣泛。 –

回答

0

如果我udnerstand你的問題正確,您通常通過抓住該線程的SycnhronizationContext然後呼喚PostSend它給它的工作發送任務轉移到其他方面的theads。問題在於,在控制檯應用程序和Windows服務中,默認SycnhronizationContext與所有線程池線程關聯,因此您發送它的工作可以在任何線程上運行。

但是Stephe Toub has an example如何創建自定義SycnhronizationContext在特定線程上運行,然後當您發送它的工作將保證在該線程上運行。爲了清楚起見,我已將一些代碼粘貼到此答案中。

/// <summary>Provides a pump that supports running asynchronous methods on the current thread. </summary> 
public static class AsyncPump 
{ 
    /// <summary>Runs the specified asynchronous function.</summary> 
    /// <param name="func">The asynchronous function to execute.</param> 
    public static void Run(Func<Task> func) 
    { 
     if (func == null) throw new ArgumentNullException("func"); 

     var prevCtx = SynchronizationContext.Current; 
     try 
     { 
      // Establish the new context 
      var syncCtx = new SingleThreadSynchronizationContext(); 
      SynchronizationContext.SetSynchronizationContext(syncCtx); 

      // Invoke the function and alert the context to when it completes 
      var t = func(); 
      if (t == null) throw new InvalidOperationException("No task provided."); 
      t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default); 

      // Pump continuations and propagate any exceptions 
      syncCtx.RunOnCurrentThread(); 
      t.GetAwaiter().GetResult(); 
     } 
     finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } 
    } 

    /// <summary>Provides a SynchronizationContext that's single-threaded.</summary> 
    private sealed class SingleThreadSynchronizationContext : SynchronizationContext 
    { 
     /// <summary>The queue of work items.</summary> 
     private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue = 
      new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); 
     /// <summary>The processing thread.</summary> 
     private readonly Thread m_thread = Thread.CurrentThread; 

     /// <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>Not supported.</summary> 
     public override void Send(SendOrPostCallback d, object state) 
     { 
      throw new NotSupportedException("Synchronously sending is not supported."); 
     } 

     /// <summary>Runs an loop to process all queued work items.</summary> 
     public void RunOnCurrentThread() 
     { 
      foreach (var workItem in m_queue.GetConsumingEnumerable()) 
       workItem.Key(workItem.Value); 
     } 

     /// <summary>Notifies the context that no more work will arrive.</summary> 
     public void Complete() { m_queue.CompleteAdding(); } 
    } 
} 

所以,你需要在你的主線程運行AsyncPump並給予SingleThreadSynchronizationContext你的工作線程,因此它可以發送工作,你的主線程。

void Main() 
{ 
    AsyncPump.Run(async delegate 
    { 
     var syncContext = SynchronizationContext.Current; 

     Console.WriteLine("Main thread, thradId:{0}", Thread.CurrentThread.ManagedThreadId); 

     await Task.Run(() => 
     { 
     Console.WriteLine("Background thread, thradId:{0}", Thread.CurrentThread.ManagedThreadId); 

     syncContext.Post(new SendOrPostCallback((state) => 
     { 
      Console.WriteLine("Running on main thread again, thradId:{0}", Thread.CurrentThread.ManagedThreadId); 
     }), null); 
    }); 

     Console.ReadLine(); 
    });; 

}