ETF*_*fax 2 c# multithreading compact-framework thread-safety
Compact Framework,Windows Mobile 6,C#.
我正在对紧凑框架进行一些背景线程,并且有一个问题:终止工作线程.
代码
我有以下ThreadWorker类(来自这里的代码),在执行时,将在某些点执行检查以查看它是否应该退出.....
public class ThreadWorker
{
public event EventHandler<ProgressEventArgs> OnProgress;
protected virtual void Progress(ProgressEventArgs args)
{
if (OnProgress != null)
OnProgress(this, args);
}
private void DoLongProcess()
{
// This will take a long time.
Thread.Sleep(15000);
Progress(new ProgressEventArgs("Some info for the UI to display."));
Thread.Sleep(15000);
}
public void DoSomeBackgroundWork()
{
try
{
while (!Stopping)
{
DoLongProcess();
if (Stopping) return;
DoLongProcess();
if (Stopping) return;
DoLongProcess();
if (Stopping) return;
DoLongProcess();
if (Stopping) return;
}
}
finally
{
SetStopped();
}
Console.WriteLine("DoSomeBackgroundWork: Terminating gracefully.");
}
/// <summary>
/// Lock covering stopping and stopped
/// </summary>
readonly object locker = new object();
/// <summary>
/// Whether or not the worker thread has been asked to stop
/// </summary>
bool stopping = false;
/// <summary>
/// Whether or not the worker thread has stopped
/// </summary>
bool stopped = false;
/// <summary>
/// Returns whether the worker thread has been asked to stop.
/// This continues to return true even after the thread has stopped.
/// </summary>
public bool Stopping
{
get
{
lock (locker)
{
return stopping;
}
}
}
/// <summary>
/// Returns whether the worker thread has stopped.
/// </summary>
public bool Stopped
{
get
{
lock (locker)
{
return stopped;
}
}
}
/// <summary>
/// Tells the worker thread to stop, typically after completing its
/// current work item. (The thread is *not* guaranteed to have stopped
/// by the time this method returns.)
/// </summary>
public void Stop()
{
lock (locker)
{
stopping = true;
}
}
/// <summary>
/// Called by the worker thread to indicate when it has stopped.
/// </summary>
void SetStopped()
{
lock (locker)
{
stopped = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
...以下表格启动线程......
public partial class Test : Form
{
public Test()
{
InitializeComponent();
}
private ThreadWorker myThreadWorker;
private Thread t = null;
private void Test_Load(object sender, EventArgs e)
{
myThreadWorker = new ThreadWorker();
myThreadWorker.OnProgress += new EventHandler<ProgressEventArgs>(myThreadWorker_OnProgress);
}
private void miStart_Click(object sender, EventArgs e)
{
try
{
listResults.Items.Insert(0, "Set-up Thread.");
t = new Thread(myThreadWorker.DoSomeBackgroundWork);
t.Name = "My Thread";
t.Priority = ThreadPriority.BelowNormal;
t.Start();
listResults.Items.Insert(0, "Thread started.");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void miStop_Click(object sender, EventArgs e)
{
try
{
listResults.Items.Insert(0, "Waiting for My Thread to terminate.");
listResults.Refresh();
myThreadWorker.Stop();
t.Join();
listResults.Items.Insert(0, "My Thread Finished.");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private delegate void InsertToListBoxDelegate(String text);
private void InsertToListBox(String text)
{
if (InvokeRequired)
Invoke(new InsertToListBoxDelegate(InsertToListBox), new object[] { text });
else
{
listResults.Items.Insert(0, "{0}".With(text));
listResults.Refresh();
}
}
void myThreadWorker_OnProgress(object sender, ProgressEventArgs e)
{
InsertToListBox(e.Text);
}
}
Run Code Online (Sandbox Code Playgroud)
问题
当我点击停止按钮时,它会调用...
myThreadWorker.Stop();
t.Join();
listResults.Items.Insert(0, "My Thread Finished.");
Run Code Online (Sandbox Code Playgroud)
...我期待的是ThreadWorker继续使用其当前的DoLongProcess()直到它完成,并仍然通过OnProgress事件处理程序和myThreadWorker_OnProgress将事件提升到UI.
然而,实际发生的是当OnProgress被引发时,应用程序冻结在线读...
Invoke(new InsertToListBoxDelegate(InsertToListBox), new object[] { text });
Run Code Online (Sandbox Code Playgroud)
这个问题
我怎么称呼......
myThreadWorker.Stop();
t.Join();
Run Code Online (Sandbox Code Playgroud)
...并且仍然会响应来自后台线程的事件,直到它被终止?
通过调用Thread.Join你已经阻止了UI线程.通过调用Control.Invoke你已经阻止了工作线程.Invoke将消息发布到UI线程的消息队列并等待它被处理.但是,由于UI线程被阻塞等待工作线程完成,因此无法开始执行转向强制工作线程停止的委托.线程现在陷入僵局.
最大的问题是Join电话.最好避免Join从UI线程调用.而是在单击后禁用停止按钮,以向用户提供已接受停止请求并处于待处理状态的反馈.您甚至可能希望在状态栏上显示一条简单的消息,说明清楚.然后,当最后一个OnProgress事件被引发时,这将是你的线程终止的信号,你可以重置表单上的所有内容.
但是,您可能想要考虑思想的根本转变.我认为这种Control.Invoke方法被过度使用了.而不是使用Control.Invoke将事件处理程序的执行编组回UI线程,您可以使用计时器对进度信息进行UI线程轮询.当有新的进度信息时,工作人员会将其发布到某个变量或数据结构.这有几个优点.
Control.Invoke强加的UI和工作线程之间的紧密耦合.| 归档时间: |
|
| 查看次数: |
6188 次 |
| 最近记录: |