在C#中处理线程状态的模式

时间:2011-03-30 07:09:51

标签: c# multithreading design-patterns

我目前正在开发一个必须处理多个线程的程序。当我启动程序时,我运行多个线程(我的示例仅限于一个)。我必须在一个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 个答案:

答案 0 :(得分:3)

对我来说看起来很好。实际上你使用观察者模式。这只是c#的漂亮事件语法,它消除了界面并减少了样板。

然而,那里存在大量冗余代码和其他可读性问题。

  • 指定thisthis.textBox1等内容时,this.Invoke(...)限定符是多余的。
  • 尝试始终为方法指定privatepublic等可见性。
  • 在方法组周围自动创建合适的委托,从而启用简写语法。例如:new Thread(myThread.MyJob)myThread.Changed += myThread_Changed
  • 考虑使用简单的Action作为事件处理程序委托类型而不是自定义(ChangedCallback)。然后myThread_Changed方法可以接受一个int作为单个参数,允许您删除大量冗余类型。
  • 为避免出现问题,请在检查null和调用之前制作事件的线程局部副本。

像这样:

JobEventHandler tmp = Changed;
if (tmp != null) tmp(this, e);

答案 1 :(得分:3)

您的代码不是很好。

  1. 为什么不让你的线程类创建线程?它更合乎逻辑,并提供了一个很好的封装:
  2. 你不应该在一个类中声明委托,它会使重构变得更难。
  3. 如果您在线程中睡觉,为什么不使用Timer
  4. 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);