【发布时间】:2014-04-09 16:10:48
【问题描述】:
我是新来的,总是在这里找到有用的线程,但在这种情况下不是。我的程序使用线程时遇到问题。特别是,我的线程在后台做一些图像模式,一切似乎都很好。 它还可以在未定义的时间(有时是 15 秒,有时是几分钟)内工作,没有任何异常或冻结或其他任何情况。但随后我的 GUI 冻结,而不是我的整个 GUI,只是从线程更新的 GUI 部分。另外两个图片框工作正常(流式传输视频),但其余的不工作。 试图在它所在的位置停止线程是可行的,但是从那里启动它会使我的程序崩溃。 没有抛出任何异常。如有必要,每个 GUI 元素都会通过 Invoke() 进行更新。我只处理图片的副本以避免任何锁定模式或其他任何事情。我也尝试让 UI 做它需要做的事情(DoEvents()) 一些想法? 代码:
namespace My.Name.Space
{
public class MyThread : MyThreadBase
{
public MyThread ( getting object s from the form for updating UI elements)
{
//referencing objects
Stopwatch.Start();
}
//example Method for UI updating
private void UpdateRobot1Box(int angle, int x, int y)
{
if (_rob1.InvokeRequired)
{
_rob1.Invoke(new Action(() => _rob1.Clear()));
_rob1.Invoke(new Action(() => _rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString()));
}
else
{
_rob1.Clear();
_rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString();
}
}
protected override void Loop(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
if( PictureBox != null && Stopwatch.ElapsedMilliseconds >= tick)
{
//DoWork
Application.DoEvents();
}
else
{
Thread.Sleep(1);
}
}
}
}
}
}
编辑 1:
MyThreadBase:
namespace My.Name.Space
{
public abstract class MyThreadBase : DisposableBase//just some simple gc stuff
{
private CancellationTokenSource _cancellationTokenSource;
public bool IsAlive
{
get { return _cancellationTokenSource != null; }
}
public event Action<Object, Exception> UnhandledException;
public void Start()
{
if (_cancellationTokenSource != null)
return;
lock (this)
{
if (_cancellationTokenSource != null)
return;
_cancellationTokenSource = new CancellationTokenSource();
var thread = new Thread(RunLoop) {Name = GetType().Name};
thread.Start();
}
}
public void Stop()
{
if (_cancellationTokenSource == null)
return;
lock (this)
{
if (_cancellationTokenSource == null)
return;
_cancellationTokenSource.Cancel();
}
}
public void Join()
{
while (IsAlive) Thread.Sleep(1);
}
private void RunLoop()
{
try
{
CancellationToken token = _cancellationTokenSource.Token;
Loop(token);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception)
{
OnException(exception);
}
finally
{
lock (this)
{
CancellationTokenSource cancellationTokenSource = _cancellationTokenSource;
_cancellationTokenSource = null;
cancellationTokenSource.Dispose();
}
}
}
protected abstract void Loop(CancellationToken token);
protected virtual void OnException(Exception exception)
{
Trace.TraceError("{0} - Exception: {1}", GetType(), exception.Message);
Trace.TraceError(exception.StackTrace);
OnUnhandledException(exception);
}
protected virtual void OnUnhandledException(Exception exception)
{
if (UnhandledException != null)
UnhandledException(this, exception);
}
protected override void DisposeOverride()
{
Stop();
}
}
UpdateRobot1Box 在线程内的 switch-case 构造中被调用。我有一个小顺序,我通过自己创建的对象列表来决定在我的文本框中写什么。
【问题讨论】:
-
Thread.Sleep 可能无济于事
-
我认为需要发布更多代码。
MyThreadBase是什么,UpdateRobot1Box怎么称呼? -
@DustinDavis 执行
Thread.Sleep(1)允许线程在while循环中不会不断地最大化CPU/核心。只需 1 毫秒就有很大帮助。 -
Sleep(1),(无意义,向下舍入为 0)和 'Application.DoEvents()',(尤其是来自非 GUI 线程)。你注定要失败。
-
应避免使用此类原语(线程类)进行异步编程,您应该考虑使用 TPL(Task
)或 Rx(响应式扩展)。对我来说最大的问题是使用 Application.DoEvents 来保持 UI 响应 - 这应该避免并且是代码异味的标志。
标签: c# multithreading user-interface freeze