Синхронизация событий из разных потоков в консольном приложении - PullRequest
4 голосов
/ 04 июля 2011

Я чувствую себя полным нубом, спрашивающим об этом, но в любом случае, вот оно:

Мне было интересно, как проще всего синхронизировать события из разных потоков.

Пример кода:

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 ]

6 голосов
/ 04 июля 2011

Вы можете попробовать 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));
}
0 голосов
/ 04 июля 2011

Если я вас правильно понял, вы спрашиваете, как выполнить код, запущенный в потоке, в другой поток.то есть: у вас есть два потока, в то время как вы выполняете код второго потока, который вы хотите выполнить в первом потоке.

Вы можете достичь этого с помощью 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".проверьте этот пример.

Редактировать: Из-за того, что вы используете консольное приложение и поэтому не можете использовать SynchronizationContext.Current.тогда вам, вероятно, нужно создать свой собственный SynchronizationContext, , этот пример может помочь.

...