Windows Service从主线程调用方法

时间:2015-01-05 01:01:13

标签: c# service

我想在工作线程的上下文中从主线程中执行一个方法,我不知道如何做到这一点。

详细说明:

  1. 主要服务开始
  2. 工作线程已启动
  3. 在工作线程中我想调用一个方法,但不是在工作线程上下文
  4. 有人可以给我一个如何执行此操作的提示吗?

1 个答案:

答案 0 :(得分:0)

如果我正确地提出了你的问题,你通常会抓住那个帖子SycnhronizationContext,然后在PostSend上打电话给其他情境。工作。问题是在控制台应用程序和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();
    });;

}