具有启动、暂停和停止事件处理的动态线程
我创建了示例应用程序并实现了线程。基本上,创建这个应用程序的目的是我想
- 如果有任何进程正在运行,那么用户界面应该通知 [DONE]
- 使用 ProgressBar 处理动态创建的线程 [DONE]
- 提供启动、暂停和停止线程的附加功能 可用进度列表。 [需要您的帮助]
注意:-我对线程和委托了解不多,所以请让我知道现有代码的最佳解决方案。
使用文件和控件:- 该演示应用程序基本上使用了三个文件
ProgressForm.cs(窗口表单) 其中包含用于创建新进度的按钮和用于保存所有创建的进度条的容器
ProgressClass.cs 其中包含动态线程和通知 UI 的委托,无需锁定或挂起用户界面
- ProgressControl.cs(用户控件)
- 其中包含
- 进度条(显示已完成的流程)
- Precent 标签(显示已完成进度的百分比)
- 开始/暂停按钮(用于播放/暂停线程)
- 停止按钮(停止正在运行的线程并从列表中删除进度)
- StartTime 标签(显示进程开始时间)
- EndTime 标签(显示进程完成时间)
- MaxValue 标签(生成 25 到 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.
}
更新:
I have created sample application and implemented threading. basically aim to craete this application is i would like to
- If any process(s) are runnig then User Interface should Notify
[DONE] - Handle dynamically created thread with ProgressBar [DONE]
- Provide addition functionality to Start, Pause and Stop thread from
available progress list. [NEED YOUR HELP]
Note:- I don't have much knowledge about Threading and Delegates, so please let me know best solution for existing code.
Files and Controls are used:-
Basically three files are used in this demo application
ProgressForm.cs (Window Form)
which conatains Button for creating new progress and Container whic will hold all the created progressbarsProgressClass.cs
Which contains Dynamic Threading and Delegates to Notify UI without locking or hanging user interface- ProgressControl.cs (User Control)
- Which contains
- Progressbar (to display process done)
- Precent Label (display percentage of completed progress)
- Start/Pause button (for play/pause a thread)
- Stop button (stop running thread and remove progress from list)
- StartTime Label (display process started time)
- EndTime label (display time of process completed)
- MaxValue Lable (generate random number between 25 to 100)
CODE SNIPPET:-
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);
}
}
I am not asking for write whole code instead of provide hint.
I would like to start/pause relevent thread from list, os what should i do for that?
I would like hind in following function:
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.
}
UPDATED:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您将需要使用
ManualResetEvent
或ManualResetEventSlim
在线程中创建暂停和恢复行为。这个想法是在安全点检查工作线程中事件的状态。这是通过WaitOne
或Wait
方法完成的。如果事件发出信号,则调用将立即返回,允许线程继续进行。如果事件未发出信号,则调用将阻塞,直到通过Set
方法发出事件信号。因此,要暂停线程,您可以调用Reset
来取消事件信号,并恢复线程,您可以调用Set
。只需记住在工作线程的指令序列中的安全点处调用
WaitOne
或Wait
即可。换句话说,不要在锁或类似的东西内调用这些方法。在循环的开始或结束通常是一个好的开始。此外,您似乎使用
Invoke
方法来更新 UI。这一切都很好,但对于简单地使用进度信息更新 UI 有一个更好的选择。最好将进度信息发布到共享数据结构,然后让 UI 线程通过计时器获取它。我知道,对于那些关注我答案的人来说,我经常谈论这个问题。但是,这种策略有很多优点。Invoke
强加的 UI 和工作线程之间的紧密耦合。Invoke
是一项昂贵的操作。更新:
以下是有关可对
ProgressStartStop
进行更改的总体思路。You will want to use a
ManualResetEvent
orManualResetEventSlim
to create the pause and resume behavior in the thread. The idea is to check the state of the event in the worker thread at safe points. This is done via theWaitOne
orWait
methods. If the event is signaled then the calls will return immediately allowing the thread to proceed. If the event is unsignaled then the calls block until the event is signaled via theSet
method. So to pause the thread you would callReset
to unsignal the event and to resume the thread you would callSet
.Just remember to place calls to
WaitOne
orWait
at safe points in the instruction sequence of the worker thread. In other words, do not call these methods inside alock
or something like that. At the beginning or end of a loop is often a good start.Also, it looks like you use the
Invoke
method for updating the UI. That is all fine and good, but for simply updating the UI with progress information there is a better option. It is better to publish the progress information to a shared data structure and then have the UI thread pick it up via a timer. For those that monitor my answers I harp about this a lot, I know. But, this strategy has a lot of advantages.Invoke
imposes.Invoke
is an expensive operation.Update:
Here is the general idea regarding the changes that could be made to
ProgressStartStop
.通常认为挂起线程是不好的做法(尽管它是可能的) 。暂停和终止线程的正确方法是通过与线程正在执行的作业配合。该作业应检查循环中的变量,并相应地暂停或退出。控制程序可以设置该变量,如果需要反馈,后台线程可以在退出或休眠之前调用通知方法。
It is generally considered bad practice to Suspend threads (though it is possible). The right way to pause and terminate threads is through the cooperation with the job that the thread is doing. The job should check a variable in a loop, and pause or exit accordingly. The controlling program can set that variable, and if you need feedback the background thread can call a notification method before exiting or sleeping.