2015-01-05 4 views
0

Я хочу исключить метод из основного потока в контексте рабочего потока, и я не знаю, как это сделать.Метод вызова службы Windows из основного потока

Подробно:

  1. Главная Serivce начал
  2. Worker Thread начал
  3. Внутри рабочего потока Я хочу, чтобы вызвать метод, но не в контексте рабочего потока

Может кто-нибудь подскажет мне, как это сделать?

+0

Вы хотите сделать это по определенной теме или какой-либо рабочий поток? –

+1

Пожалуйста, объясните, почему «не в контексте рабочего потока»? Что это касается основного потока вашего сервиса, который мотивирует вас на то, что вы хотите использовать этот метод, а не в рабочем потоке? Что случилось бы, если бы вы просто вызвали метод в рабочем потоке? В вашем вопросе отсутствуют важные сведения, которые потребуются для обеспечения хорошего ответа, и чтобы сузить вопрос, чтобы он был не таким широким. –

ответ

0

Если я udnerstand вашего вопроса правильно, вы обычно отправить работу на theads другого контекста, захватывая, что нити SycnhronizationContext и затем называют Post или Send на него, чтобы дать ему работу. Проблема заключается в том, что в консольных приложениях и службах 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(); 
    });; 

} 
Смежные вопросы