Windows Service 从主线程调用方法

本文关键字:调用 方法 线程 Service Windows | 更新日期: 2023-09-27 18:36:24

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

详细地:

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

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

Windows Service 从主线程调用方法

如果我正确理解了您的问题,您通常会通过抓取该线程的SycnhronizationContext然后调用PostSend来将工作发送给另一个上下文的负责人以赋予它工作。问题在于,在控制台应用和 Windows 服务中,默认SycnhronizationContext与所有线程池线程相关联,因此您发送它的工作可以在任何线程上运行。

但是,Stephe Toub 有一个示例,说明如何创建自定义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();
    });;
}