【问题标题】:Pattern to handle threads status in C#在 C# 中处理线程状态的模式
【发布时间】:2011-03-30 23:39:56
【问题描述】:

我目前正在开发一个必须处理多个线程的程序。当我启动程序时,我运行多个线程(我的示例仅限于一个)。我必须在单个文本框中显示它们的状态。我选择了下一个解决方案。这种方式正确吗?还有其他模式吗?也许是观察者?我在网络上找不到执行此操作的好方法。

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

【问题讨论】:

    标签: c# multithreading design-patterns


    【解决方案1】:

    在我看来还不错。事实上,您正在使用观察者模式。这只是 c# 的不错的事件语法,消除了接口并减少了样板。

    但是,其中存在大量冗余代码和其他可读性问题。

    • 在指定this.textBox1this.Invoke(...) 等成员时,this 限定符是多余的。
    • 尝试始终为方法指定可见性,例如 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 - 我不认为关于网络的事情真的增加了任何东西。
    • 这确实是观察者模式。知道我明白。首选示例 (en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Observer)。谢谢。
    • @Patrick Klug ops,误解了这个问题 - 认为问题的一部分是“这在网络环境中效果不佳”...... :-P
    【解决方案2】:

    你的代码不好。

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

    【讨论】:

    • 1.正确的。 2. 正确 3. Thread.Sleep(1000) 应该读作 // Do work... 谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    相关资源
    最近更新 更多