2013-10-25 5 views
1

Я ищу решение для interthread общения. Тема А является основной нитью приложения Windows. Я запускаю Thread B, который работает независимо от потока a, они не используют код. Но нить A должна получить некоторую обратную связь о состоянии потока b. Я пытаюсь решить это с помощью делегата. Мне очень жаль, что я забыл добавить, что я должен работать на .NET 3.5, C#, WEC7Связь между потоками через делегатов?

Важно, что код

public void OnMyEvent(string foo) 
     { 
      MessageBox.Show(foo); 
     } 

выполняется в контексте потока а, как может Я достигнуть этого

public partial class Form1 : Form 
{ 
//... 
    public void StartThread(Object obj) 
    { 
     new ClassForSecondThread(obj as Parameters);    
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     //ParameterizedThreadStart threadstart = new ParameterizedThreadStart(startThread); 
     ParameterizedThreadStart threadstart = new ParameterizedThreadStart(StartThread); 
     Thread thread = new Thread(threadstart); 
     Parameters parameters = new Parameters(){MyEventHandler = OnMyEvent}; 
     thread.Start(parameters);       
    } 

    public void OnMyEvent(string foo) 
    { 
     MessageBox.Show(foo); 
    } 
} 

//This code is executed in Thread B 
public class ClassForSecondThread 
{ 
    public ClassForSecondThread(Parameters parameters) 
    { 
     if (parameters == null) 
      return; 
     MyEventhandler += parameters.MyEventHandler; 
     DoWork(); 
    } 

    private void DoWork() 
    { 
     //DoSomething 
     if (MyEventhandler != null) 
      MyEventhandler.DynamicInvoke("Hello World");// I think this should be executed async, in Thread A 
     Thread.Sleep(10000); 
     if (MyEventhandler != null) 
      MyEventhandler.DynamicInvoke("Hello World again"); // I think this should be executed async, in Thread A 
    } 

    public event MyEventHandler MyEventhandler; 
} 
public class Parameters 
{ 
    public MyEventHandler MyEventHandler; 
} 

public delegate void MyEventHandler(string foo); 
+0

Ваш пример кода очень важен для реальной проблемы с таким подходом. Ничего не происходит в течение 10 секунд, поэтому пользователь сдался и закрыл окно. Это не закончится хорошо. –

+0

Перейдите к параллельной библиотеке задач http://msdn.microsoft.com/en-us/library/dd460717.aspx –

+0

@ Ханс Пассант: но есть возможность для Главного потока знать, есть еще один поток работает, не так ли? На следующем шаге важно, чтобы иметь возможность вызывать код в потоке b два, чтобы остановить поток внешнего устройства и остановить себя – traveller

ответ

2

Как вы хотите, чтобы вызвать MessageBox на главном потоке пользовательского интерфейса, вы можете добиться того, что вы хотите с помощью Control.Invoke.

 Invoke((MethodInvoker)(() => MessageBox.Show(foo))); 

Invoke метод может быть вызван непосредственно на форме, и вы не будете в контексте тему В рамках делегата - код будет работать на тот же поток, что и форма.

EDIT: Вопрос OP: если я понял Control.Invoke правильно, он всегда действует в контексте элемента управления?

Хотя метод Invoke использует элемент управления (в данном случае для формы), чтобы получить дескриптор потока пользовательского интерфейса, он работает, код внутри делегата не является специфическим для пользовательского интерфейса. Если вы хотите добавить несколько операторов и расширить его, чтобы включить больше вещей, просто сделать это:

 string t = "hello"; //declared in the form 

     //Thread B context - Invoke called 
     Invoke((MethodInvoker)(() => 
      { 
       //Back to the UI thread of the Form here == thread A 
       MessageBox.Show(foo); 
       t = "dd"; 
      })); 

Кроме того, если вы обновляете вещи в многопоточных среде, где данные доступны более чем одной нити, то вам нужно будет исследовать sychronization - применение замки данных и т.д.

+0

Но это покажет окно сообщения в контексте потока A, основной ветки Windows , и OP заявили, что хотят, чтобы это было показано в контексте потока B. Хотя я думаю, что OP не очень ясен ... –

+0

Извините, я видел, что сейчас была ошибка, и я ее отредактировал, Я имел в виду thread a ... Правильно, это выполняется в контексте потока b. Извините – traveller

+0

@Jaycee: Большое спасибо за ваш ответ. В реальном приложении код, который должен будет выполняться, находится в UI Tread, но это не просто UIcode, и если я правильно понял Control.Invoke, он всегда действует в контексте элемента управления – traveller

0

для чего это стоит вы можете упростить ваш код значительно, используя новые async и await ключевые слова в C# 5.0.

public class Form1 : Form 
{ 
    private async void button1_Click(object sender, EventArgs args) 
    { 
    OnMyEvent("Hello World"); 
    await Task.Run(
    () => 
     { 
     // This stuff runs on a worker thread. 
     Thread.Sleep(10000); 
     }); 
    OnMyEvent("Hello World again"); 
    } 

    private void OnMyEvent(string foo) 
    { 
    Message.Show(foo); 
    } 

} 

В приведенном выше OnMyEvent кода выполняется в потоке пользовательского интерфейса в обоих случаях. Первый вызов должен быть выполнен до запуска задачи, а второй вызов будет выполнен после завершения задачи.

Смежные вопросы