替代无限循环

时间:2013-05-15 19:39:20

标签: c# timer schedule long-running-processes

我有一个无限循环: -

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();  
}

任何见解/建议/建议都会受到欢迎......

2 个答案:

答案 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函数(或特定工具包调用它),然后窗口工具包为您调用函数。你不要告诉它自己画画,或者不必担心等待条件或类似的事情。所以,听起来你可能误解了如何使用你正在使用的窗口工具包。