我有一个无限循环: -
while(true)
{
//display an image
}
显然CPU上升了。
我用过:
Thread.Sleep(100);
Thread.Sleep(0);
ApplicationDoEvents() - I know i shouldn't
除非应用程序结束,否则此循环将永远不会结束。它们是无限循环的其他替代方案吗?
我正在用户控件中显示图像,而我正在覆盖OnPaint
事件......
if (CurrentFrame != null)
{
g.DrawImageUnscaled(CurrentFrame, 0,0);
}
public void NewFrame(Image _currentFrame)
{
if (CurrentFrame != null)
{
CurrentFrame.Dispose();
}
CurrentFrame = _currentFrame;
Invalidate();
//Update();
}
任何见解/建议/建议都会受到欢迎......
答案 0 :(得分:3)
你可以在这里做几件事。第一种是使用计时器以标准速率进行更新。如果您使用的是Windows窗体,则可以在窗体上放置一个Timer组件,并将周期设置为15 ms。这将给你(大约)每秒66次帧更新。
请注意,.NET计时器最多只能提供15毫秒的分辨率。您可以使用自己的一个Windows计时器实现为1 ms的分辨率,但这样做会使代码复杂化。
您可以做的另一件事是让更新CurrentFrame
图像的代码调用更新方法,并使更新方法不会比某些设置速率更频繁地更新。您可以通过在程序开头使用Stopwatch
并检查自上次更新后经过的时间来完成此操作。类似的东西:
private Stopwatch FrameTimer = Stopwatch.StartNew();
private long LastUpdateTime = 0;
private const long MinUpdateMs = 10; // minimum time between updates
void DoUpdate()
{
long currentTime = FrameTimer.ElapsedMilliseconds;
if ((currentTime - LastUpdateTime) < MinUpdateMs)
{
// updated within the last 10 ms
return;
}
LastUpdateTime = currentTime;
if (CurrentFrame != null)
{
g.DrawImageUnscaled(CurrentFrame, 0,0);
}
}
第二个选项非常有效,但如果没有持续更改,您可能会面临无法获得上次更新的风险。如果您的CurrentFrame
更新之间可能有很长一段时间,那么您可以使用一个计时器,每隔一秒左右强制更新一次。如果这样做,您希望在DoUpdate
方法中添加一些同步以防止并发更新。我建议:
private object UpdateLock = new object();
void DoUpdate()
{
if (!Monitor.TryEnter(UpdateLock))
{
// update already in progress
return;
}
try
{
long currentTime = FrameTimer.ElapsedMilliseconds;
if ((currentTime - LastUpdateTime) < MinUpdateMs)
{
// updated within the last 10 ms
return;
}
LastUpdateTime = currentTime;
if (CurrentFrame != null)
{
g.DrawImageUnscaled(CurrentFrame, 0,0);
}
}
finally
{
Monitor.Exit(UpdateLock);
}
}
答案 1 :(得分:1)
当某个条件为真时需要线程休眠时,正常的做法是使用condition variable。线程锁定互斥锁,然后将其传递给条件变量并阻塞(然后临时释放互斥锁上的锁定)。然后,当它正在等待的条件为真时,使该条件为真的线程发出条件变量的信号,并且该线程唤醒,重新获取互斥锁上的锁,并继续其快乐方式。值得注意的是,条件变量可能有虚假的唤醒(有时多个线程可能在相同条件下等待),因此需要有某种标志来指示条件何时为真,并且当线程从条件变量中唤醒时,如果该标志不为真,它将检查该标志并再次阻塞条件变量。与条件变量一起使用的互斥锁也用于保护该标志。
D运行时在core.sync.condition
中有一个条件变量。
还有其他关于堆栈溢出的条件变量的好问题,例如:condition variable
现在,至于你的特定用例,我必须同意Idan Arye的评论,你似乎有点想用壁画工具包绘画来做这件事。通常,它的工作方式是覆盖OnPaint
函数(或特定工具包调用它),然后窗口工具包为您调用函数。你不要告诉它自己画画,或者不必担心等待条件或类似的事情。所以,听起来你可能误解了如何使用你正在使用的窗口工具包。