Шаблон для обработки статуса потоков в C # - PullRequest
2 голосов
/ 30 марта 2011

В настоящее время я разрабатываю программу, которая должна обрабатывать несколько потоков.Когда я запускаю программу, я запускаю несколько потоков (мой пример ограничен одним).Я должен отобразить их статус в одном TextBox.Я выбрал следующее решение.Это правильный путь?Есть ли другой шаблон?Наблюдатель что ли?Я не могу найти хороший способ сделать это в Интернете.

namespace ThreadTest
{
    public partial class Form1 : Form
    {
        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        delegate void ChangedCallback(object sender, JobEventArgs e);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            MyThread myThread = new MyThread();
            myThread.Changed += new MyThread.JobEventHandler(myThread_Changed);

            // Create the thread object, passing in the Alpha.Beta method
            // via a ThreadStart delegate. This does not start the thread.
            Thread oThread = new Thread(new ThreadStart(myThread.MyJob));

            // Start the thread
            oThread.Start();
        }

        void myThread_Changed(object sender, JobEventArgs e)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {
                ChangedCallback d = new ChangedCallback(myThread_Changed);
                this.Invoke(d, new object[] { sender, e });
            }
            else
            {
                // Display the status of my thread
                textBox1.Text += e.Counter;
            }
        }
    }

    public class MyThread
    {
        // A delegate type for hooking up change notifications.
        public delegate void JobEventHandler(object sender, JobEventArgs e);

        // An event that clients can use to be notified whenever the
        // elements of the list change.
        public event JobEventHandler Changed;

        // Invoke the Changed event; called whenever list changes
        protected virtual void OnChanged(JobEventArgs e)
        {
            if (Changed != null)
                Changed(this, e);
        }

        public void MyJob()
        {
            for (int i = 0; i < 1000; i++)
            {
                Thread.Sleep(1000);
                JobEventArgs e = new JobEventArgs(i);
                OnChanged(e);
            }
        }
    }

    public class JobEventArgs
    {

        public int Counter { get; set; }

        public JobEventArgs(int i)
        {
            Counter = i;
        }
    }
} 

Ответы [ 2 ]

3 голосов
/ 30 марта 2011

Ваш код не в порядке.

  1. Почему вы не позволяете вашему классу потока создавать поток? Это более логично и дает хорошую инкапсуляцию:
  2. Вы не должны объявлять делегатов внутри класса, это усложняет рефакторинг.
  3. Если вы спите в ветке, почему бы вам не использовать Timer вместо этого?

#

public partial class Form1
{
    delegate void ChangedCallback(object sender, JobEventArgs e);

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        MyThread myThread = new MyThread();
        myThread.Changed += myThread_Changed;
        myThread.Start();
    }

    void myThread_Changed(object sender, JobEventArgs e)
    {
        if (this.textBox1.InvokeRequired)
        {
            ChangedCallback d = new ChangedCallback(myThread_Changed);
            this.Invoke(d, new object[] { sender, e });
        }
        else
        {
            textBox1.Text += e.Counter;
        }
    }
}


public class MyThread
{
    private Thread _thread;

    public MyThread()
    {
        _thread = new Thread(WorkerFunc);
    }

    public void Start()
    {
        _thread.Start();
    }

    // use the = {} pattern since you are using multithreading.
    public event JobEventHandler Changed = {};

    protected virtual void OnChanged(JobEventArgs e)
    {
        Changed(this, e);
    }

    private void WorkerFunc()
    {
        for (int i = 0; i < 1000; i++)
        {
            Thread.Sleep(1000);
            JobEventArgs e = new JobEventArgs(i);
            OnChanged(e);
        }
}

// A delegate type for hooking up change notifications.
public delegate void JobEventHandler(object sender, JobEventArgs e);
3 голосов
/ 30 марта 2011

Это выглядит очень хорошо для меня.На самом деле вы используете шаблон наблюдателя.Это просто приятный синтаксис событий в c #, исключающий интерфейс и сокращающий шаблон.

Однако в нем много избыточного кода и других проблем с читаемостью.

  • Квалификатор thisизбыточно при указании члена, такого как this.textBox1 или this.Invoke(...).
  • Старайтесь всегда указывать видимость, например private или public для методов.
  • Подходящий делегат создается автоматическивокруг группы методов, включающей сокращенный синтаксис.Например: new Thread(myThread.MyJob) или myThread.Changed += myThread_Changed.
  • Подумайте об использовании простого Action в качестве типов делегатов обработчика событий вместо пользовательских (ChangedCallback).Затем метод myThread_Changed может просто принять int как один параметр, позволяющий отбрасывать множество избыточных типов.
  • Во избежание проблем создайте локальную копию потока события, прежде чем проверять его на нулевое значение и вызывать.

Как это:

JobEventHandler tmp = Changed;
if (tmp != null) tmp(this, e);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...