我有一个无限循环:-
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();
}
任何见解/建议/建议都是非常欢迎的… 您可以在这里做几件事。第一种是使用计时器以标准速率进行更新。如果你使用的是Windows窗体,你可以在窗体上放置一个Timer组件,并将周期设置为15毫秒。这将使你(大约)每秒更新66帧。
请注意,. net计时器最多只能提供大约15毫秒的分辨率。你可以滚动你自己的一个Windows计时器的实现来给你1毫秒的分辨率,但是这样做会使你的代码变得非常复杂。
您可以做的另一件事是让更新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);
}
}
当您需要线程休眠直到某个条件为真时,通常要做的事情是使用条件变量。线程锁定互斥锁,然后将其传递给条件变量并阻塞(然后暂时释放互斥锁上的锁)。然后,当它等待的条件为真时,使该条件为真的线程向条件变量发出信号,然后该线程醒来,重新获得互斥锁,然后继续它的快乐之路。需要注意的是,条件变量可能有虚假的唤醒(有时多个线程可能等待相同的条件),所以需要有某种标志来指示条件何时为真,当线程从条件变量唤醒时,它会检查该标志,如果标志不为真,则再次阻塞条件变量。与条件变量一起使用的互斥锁也用于保护该标志。
D运行时在core.sync.condition
中有一个条件变量
还有其他关于堆栈溢出条件变量的好问题,例如:条件变量
现在,对于您的特定用例,我不得不同意Idan Arye的评论,即您将尝试使用窗口工具包进行绘画,这似乎有点离谱。通常,它的工作方式是您覆盖OnPaint
函数(或任何特定工具包调用它),然后窗口工具包为您调用该函数。你不用让它给自己涂上颜色,也不用担心等待某种情况的出现。所以,听起来你可能误解了如何使用你正在使用的窗口工具包