3

我有一个无限循环:-

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

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

4

2 回答 2

3

您可以在这里做几件事。第一种是使用计时器以标准速率进行更新。如果您使用的是 Windows 窗体,则可以在窗体上放置一个计时器组件并将周期设置为 15 毫秒。这将给你(大约)每秒 66 帧更新。

请注意,.NET 计时器最多可为您提供大约 15 毫秒的分辨率。您可以滚动您自己的 Windows 计时器之一的实现,以提供 1 毫秒的分辨率,但这样做会使您的代码变得非常复杂。

您可以做的另一件事是让更新CurrentFrame图像的代码调用更新方法,并让更新方法的更新频率不超过某个设定的速率。您可以通过Stopwatch在程序开头启动 a 并检查自上次更新以来经过的时间来执行此操作。就像是:

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);
    }
}
于 2013-05-16T15:19:22.493 回答
1

当您需要线程休眠直到某些条件为真时,通常要做的事情是使用条件变量. 线程锁定互斥体,然后将其传递给条件变量并阻塞(然后暂时释放互斥体上的锁)。然后,当它等待的条件为真时,使该条件为真的线程向条件变量发出信号,该线程唤醒,重新获得互斥锁上的锁,并继续其愉快的方式。不过要注意的是条件变量可能会产生虚假唤醒(有时多个线程可能会在同一条件下等待),因此需要有某种标志来指示条件何时为真,并且当线程从条件变量中唤醒时,它会检查该标志并在标志不为真时再次阻塞条件变量。与条件变量一起使用的互斥锁也用于保护该标志。

D 运行时有一个条件变量core.sync.condition

还有其他与堆栈溢出条件变量有关的好问题,例如:条件变量

现在,对于您的特定用例,我必须同意 Idan Arye 的评论,即您尝试使用窗口工具包进行绘画似乎有点不对劲。通常,它的工作方式是您覆盖该OnPaint函数(或任何特定工具包调用的函数),然后窗口工具包为您调用该函数。你不会告诉它自己画,也不必担心等待条件或类似的事情。因此,听起来您可能误解了如何使用您正在使用的窗口工具包。

于 2013-05-15T23:44:14.053 回答