Windows 从主线程调用服务方法

Windows Service invoke method from main thread

我想在工作线程的上下文中从主线程执行一个方法,但我不知道该怎么做。

详细:

  1. 主服务已启动
  2. 工作线程已启动
  3. 我想在工作线程中调用一个方法,但不在工作线程上下文中

有人可以提示我如何执行此操作吗?

如果我正确理解了你的问题,你通常会通过获取该线程的 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();
    });;

}