同步控制台应用程序中不同线程的事件

时间:2011-07-04 11:05:18

标签: c# multithreading console-application task

我感觉自己就像一个总的菜鸟问这个,但无论如何,这里就是:

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

一些示例代码:

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);
        }
    }
}

正如你可能猜到的那样,只有第一个写字线在主线程上执行,其他调用都在任务创建的新线程上执行。

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

2 个答案:

答案 0 :(得分:6)

您可以尝试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));
}

答案 1 :(得分:-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示例可能有帮助。