【问题标题】:Dynamic Threading with Start, Pause and Stop event handling具有启动、暂停和停止事件处理的动态线程
【发布时间】:2011-09-09 13:34:51
【问题描述】:

我已经创建了示例应用程序并实现了线程。基本上旨在创建这个应用程序是我想要的

  1. 如果有任何进程正在运行,则用户界面应通知 [完成]
  2. 使用 ProgressBar 处理动态创建的线程 [DONE]
  3. 为启动、暂停和停止线程提供附加功能 可用的进度列表。 [需要你的帮助]

注意:-我对线程和委托了解不多,所以请告诉我现有代码的最佳解决方案。

使用了文件和控件:- 在这个演示应用程序中基本上使用了三个文件

  1. ProgressForm.cs(窗口窗体) 其中包含用于创建新进度的 Button 和将保存所有已创建进度条的 Container

  2. ProgressClass.cs 其中包含动态线程和委托通知 UI,无需锁定或挂起用户界面

  3. ProgressControl.cs(用户控制)
  4. 其中包含
  5. 进度条(显示已完成的流程)
  6. Precent 标签(显示完成进度的百分比)
  7. 开始/暂停按钮(用于播放/暂停线程)
  8. 停止按钮(停止运行线程并从列表中删除进度)
  9. StartTime 标签(显示进程开始时间)
  10. EndTime 标签(显示进程完成时间)
  11. MaxValue Lable(生成 25 到 100 之间的随机数)

代码片段:- 1。 ProgressForm .cs

public partial class ProgressForm : Form
    {
        Random randomMaxValue = new Random();
        public ProgressForm()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
             ProgressClass m_clsProcess;
             ProgressControl progress = new ProgressControl();
             progress.StartedAt = DateTime.Now;
             progress.MinValue = 0;
             progress.CurrentValue = 0;
             progress.MaxValue = randomMaxValue.Next(25, 100);
             AddControl(progress);
             m_clsProcess = new ProgressClass(progress, this, new ProgressClass.NotifyProgress(DelegateProgress));
             m_clsProcess.Start();
        }
        private void DelegateProgress(int CurrentValue, ProgressControl Progress)
        {
            ProgressBar p = (ProgressBar)Progress.Controls.Find("pgbPercent", false)[0];
            p.Minimum = Progress.MinValue;
            p.Value = CurrentValue;
            p.Maximum = Progress.MaxValue;

            Label percent = (Label)Progress.Controls.Find("lblPercent", false)[0];
            percent.Text = string.Format("{0:#00} %", Convert.ToInt16((CurrentValue * 100) / Progress.MaxValue));

            Label start = (Label)Progress.Controls.Find("lblStart", false)[0];
            start.Text = string.Format("{0:HH:mm:ss}", Progress.StartedAt);

            if (CurrentValue == Progress.MaxValue)
            {
                Label complete = (Label)Progress.Controls.Find("lblComplete", false)[0];
                complete.Text = string.Format("{0:HH:mm:ss}", DateTime.Now);
                Progress.Status = ProgressControl.ProgressStatus.Completed;
            }

            Label max = (Label)Progress.Controls.Find("lblMaxValue", false)[0];
            max.Text = string.Format("{0:#00}", Progress.MaxValue);

            Button btnstartstop = (Button)Progress.Controls.Find("btnStartStop", false)[0];
            btnstartstop.Click += new EventHandler(ProgressStartStop);
        }
        private void AddControl(Control ctl)
        {
            tableLayoutPnl.RowCount += 1;
            tableLayoutPnl.RowStyles.Add(new RowStyle());
            ctl.Dock = DockStyle.Fill;
            tableLayoutPnl.Controls.Add(ctl, 0, tableLayoutPnl.RowCount - 1);
        }
        void ProgressStartStop(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            //
            //Here i would like to write a code for START / PAUSE thread and update Image acording too.
            //
        }
    }

2。 ProgressControl.cs

public partial class ProgressControl : UserControl
    {
        public enum ProgressStatus
        {
            Initialize,
            Running,
            Paused,
            Completed
        }

        public DateTime StartedAt { get; set; }
        public DateTime CompletedAt { get; set; }
        public int MinValue { get; set; }
        public int CurrentValue { get; set; }
        public int MaxValue { get; set; }
        public ProgressStatus Status { get; set; }

        public ProgressControl()
        {
            InitializeComponent();
            this.Status = ProgressStatus.Initialize;
        }
    }

3. ProgressClass.cs

public class ProgressClass
{
    private int ThreadWaitTime = 100;
    private ProgressControl m_progress;
    private NotifyProgress m_clsNotifyDelegate;
    private System.Threading.Thread m_clsThread;

    private System.ComponentModel.ISynchronizeInvoke m_clsSynchronizingObject;
    public delegate void NotifyProgress(int PercentComplete, ProgressControl Progress);

    public ProgressClass(ProgressControl Progress, System.ComponentModel.ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
    {
        m_progress = Progress;
        m_clsSynchronizingObject = SynchronizingObject;
        m_clsNotifyDelegate = NotifyDelegate;
    }

    public void Start()
    {
        m_clsThread = new System.Threading.Thread(DoProcess);
        m_clsThread.Name = "Background Thread";
        m_clsThread.IsBackground = true;
        m_progress.Status = ProgressControl.ProgressStatus.Running;
        m_clsThread.Start();
    }
    private void DoProcess()
    {
        for (int i = m_progress.MinValue; i <= m_progress.MaxValue; i++)
        {
            NotifyUI(i);
            Thread.Sleep(ThreadWaitTime);
        }
    }
    private void NotifyUI(int Value)
    {
        object[] args = new object[2];
        args[0] = Value;
        args[1] = m_progress;
        m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
    }
}

我不是要求编写整个代码而不是提供提示。

我想从列表中启动/暂停相关线程,操作系统我应该怎么做? 我想在下面的功能后面:

   void ProgressStartStop(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            //Here i would like to write a code for START / PAUSE thread and update Image acording too.
        }

更新:

【问题讨论】:

    标签: winforms multithreading events c#-4.0 delegates


    【解决方案1】:

    您将需要使用ManualResetEvent 或ManualResetEventSlim 在线程中创建暂停和恢复行为。这个想法是在安全点检查工作线程中事件的状态。这是通过WaitOne 或Wait 方法完成的。如果事件发出信号,则调用将立即返回,允许线程继续。如果事件未发出信号,则调用会阻塞,直到通过Set 方法发出事件信号。因此,要暂停线程,您将调用Reset 以取消事件信号并恢复您将调用Set 的线程。

    只要记住在工作线程指令序列中的安全点调用WaitOne 或Wait。换句话说,不要在 lock 或类似的地方调用这些方法。在循环的开始或结束时通常是一个好的开始。

    此外,您似乎使用Invoke 方法更新用户界面。这一切都很好,但是对于简单地使用进度信息更新 UI,有一个更好的选择。最好将进度信息发布到共享数据结构,然后让 UI 线程通过计时器获取它。我知道,对于那些监视我的答案的人来说,我经常谈论这一点。但是,这种策略有很多优点。

    • 它打破了Invoke 强加的 UI 和工作线程之间的紧密耦合。
    • 它将更新 UI 线程的责任放在它本来应该属于的 UI 线程上。
    • UI 线程可以决定更新的时间和频率。
    • 不存在 UI 消息泵溢出的风险,就像工作线程启动的封送技术一样。
    • 工作线程无需等待确认更新已执行,即可继续执行后续步骤(即,您可以在 UI 和工作线程上获得更高的吞吐量)。
    • 它避免了在尝试优雅地结束工作线程时可能发生的微妙竞争条件。
    • 因为Invoke 是一项昂贵的操作,所以效率更高。

    更新:

    以下是关于可以对 ProgressStartStop 进行更改的总体思路。

    private Dictionary<int, ThreadInfo> threads = new Dictionary<int, ThreadInfo>();
    
    void ProgressStartStop(object sender, EventArgs e)
    {
      Button button = sender as Button;
      int index = GetThreadIndexFromButton(button);
      if (!threads.ContainsKey(index))
      {
        // The thread has not been started yet so do it now.
        var thread = new Thread(RunThread);
        thread.Start();
        var mres = new ManualResetEventSlim(true);
        var info = new ThreadInfo { Thread = thread, ProceedSignal = mres };
        threads.Add(index, info);
        // Change the button image here.
      }
      else
      {
        ThreadInfo info = threads[index];
        if (info.ProceedSignal.Wait(0))
        {
          // The event is signaled which means the thread is running. Pause it.
          info.ProceedSignal.Reset();
          // Change the button image here.
        }
        else
        {
          // The event is unsignaled which means the thread is paused. Resume it.
          info.ProceedSignal.Set();
          // Change the button image here.
        }
      }
    }
    
    private class ThreadInfo
    {
      Thread Thread { get; set; }
      ManualResetEventSlim ProceedSignal { get; set; }
    }
    

    【讨论】:

    • 好点,所有。关于 InvokeAsync 而不是计时器的任何想法?
    • 但我不知道在void ProgressStartStop(object sender, EventArgs e) 方法中访问线程。如果你指出这个函数中的一些代码会很有帮助
    • +1 用于使用简单的计时器向用户显示线程子系统状态,而不是让线程以通常人类不可读的速率发布消息队列阻塞的更新数量。
    • 我仍然没有得到解决方案,我对你的代码有点困惑。我可以把整个代码发给你吗?
    【解决方案2】:

    挂起线程通常被认为是不好的做法(尽管它是is possible)。暂停和终止线程的正确方法是通过与线程正在执行的工作的合作。该作业应在循环中检查变量,并相应地暂停或退出。控制程序可以设置该变量,如果您需要反馈,后台线程可以在退出或休眠之前调用通知方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-10
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 1970-01-01
      相关资源
      最近更新 更多