【问题标题】:Synchronizing events from different threads in console application在控制台应用程序中同步来自不同线程的事件
【发布时间】:2011-09-28 01:48:54
【问题描述】:

我感觉自己像个菜鸟一样问这个问题,但无论如何,就这样吧:

我想知道从不同线程同步事件的最简单方法是什么。

一些示例代码:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("# started on:" + Thread.CurrentThread.ManagedThreadId);
        tt t = new tt();

        t.First += new EventHandler(t_First);
        t.Second += new EventHandler(t_Second);

        Task task = new Task(new Action(t.Test));
        task.Start();

        while (true)
        {
            Console.ReadKey();
            Console.WriteLine("# waiting on:" + Thread.CurrentThread.ManagedThreadId);
        }
    }

    static void t_Second(object sender, EventArgs e)
    {
        Console.WriteLine("- second callback on:" + Thread.CurrentThread.ManagedThreadId);
    }

    static void t_First(object sender, EventArgs e)
    {
        Console.WriteLine("- first callback on:" + Thread.CurrentThread.ManagedThreadId);
    }

    class tt
    {
        public tt()
        {
        }

        public event EventHandler First;
        public event EventHandler Second;

        public void Test()
        {
            Thread.Sleep(1000);

            Console.WriteLine("invoked on:" + Thread.CurrentThread.ManagedThreadId);

            First(this, null);
            Thread.Sleep(1000);
            Second(this, null);
        }
    }
}

你可能已经猜到了,只有第一个 writeline 在主线程上执行,其他调用都在任务创建的新线程上执行。

我想在主线程上同步对“Second”的调用(它不应该被调用,因为我在 while 循环中阻塞)。但是我想知道这样做的方式,或者它是否可能?

【问题讨论】:

  • 我一直在考虑同样的问题。我的猜测是最好实现自己的SynchronizationContext
  • 你为什么不直接打电话给task.Wait(timeout)
  • 这不是生产力代码,甚至不是生产力问题!是的,我可能可以等。但我创建这个控制台应用程序的唯一原因是找出在这种非常特殊的情况下如何进行同步!我只是想确保我没有错过关于线程、事件、同步等重要的东西。 ..
  • 刚刚发现了一个和我非常相似的问题:stackoverflow.com/questions/3656250/…

标签: c# multithreading console-application task


【解决方案1】:

如果我理解正确,您是在询问如何将线程上运行的代码执行到不同的线程中。即:你有两个线程,而你正在执行第二个线程代码,你想在第一个线程中执行它。

你可以通过使用SynchronizationContext来实现,例如如果你想从另一个线程执行代码到主线程,你应该使用当前同步上下文:

private readonly System.Threading.SynchronizationContext _currentContext = System.Threading.SynchronizationContext.Current;

private readonly object _invokeLocker = new object();

public object Invoke(Delegate method, object[] args)
{
    if (method == null)
    {
        throw new ArgumentNullException("method");
    }

    lock (_invokeLocker)
    {
        object objectToGet = null;

        SendOrPostCallback invoker = new SendOrPostCallback(
        delegate(object data)
        {
            objectToGet = method.DynamicInvoke(args);
        });

        _currentContext.Send(new SendOrPostCallback(invoker), method.Target);

        return objectToGet;
     }
}

当您在第二个线程中时,使用此方法将在主线程上执行代码。

您可以实现ISynchronizeInvoke“System.ComponentModel.ISynchronizeInvoke”。检查this 示例。

编辑:因为你正在运行一个控制台应用程序,所以不能使用SynchronizationContext.Current。那么您可能需要设计自己的SynchronizationContextthis 示例可能会有所帮助。

【讨论】:

  • 不幸的是,这不起作用,因为 SynchronizationContext.Current 为空(它是一个控制台应用程序,而不是 Windows 窗体)
  • 您可能需要实现自己的SyncrhonizationContext 版本。
【解决方案2】:

你可以试试BlockingCollection

BlockingCollection<Action> actions = new BlockingCollection<Action>();

void main() {
   // start your tasks

   while (true) {
       var action = actions.Take();

       action();
   }
}

static void t_First(object sender, EventArgs e) {
    string message = "- first callback on:" + Thread.CurrentThread.ManagedThreadId;
    actions.Add(_ => Console.WriteLine(message));
}

【讨论】:

  • 我非常喜欢这个解决方案,因此我宣布我的问题得到了回答:)
猜你喜欢
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
相关资源
最近更新 更多