替代无限循环

本文关键字:无限循环 | 更新日期: 2023-09-27 18:13:59

我有一个无限循环:-

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函数(或任何特定工具包调用它),然后窗口工具包为您调用该函数。你不用让它给自己涂上颜色,也不用担心等待某种情况的出现。所以,听起来你可能误解了如何使用你正在使用的窗口工具包