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

ここでできることがいくつかあります。1 つ目は、タイマーを使用して標準レートで更新を行うことです。Windows フォームを使用している場合は、Timer コンポーネントをフォームにドロップして、期間を 15 ミリ秒に設定できます。これにより、1 秒あたり (約) 66 フレームの更新が行われます。

.NET タイマーでは、せいぜい約 15 ミリ秒の分解能しか得られないことに注意してください。Windows タイマーのいずれかを独自に実装して 1 ミリ秒の精度を実現できますが、そうするとコードが非常に複雑になります。

他にできることは、CurrentFrame画像を更新するコードに update メソッドを呼び出してもらい、その update メソッドを一定の設定レートよりも頻繁に更新しないようにすることです。これを行うには、プログラムの先頭で aStopwatchを開始し、最後の更新からの経過時間を確認します。何かのようなもの:

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

2 番目のオプションは非常に効果的ですが、継続的な変更がない場合、最後の更新を取得できないリスクがあります。の更新間隔が長くなる可能性がある場合CurrentFrameは、約 1 秒ごとに更新を強制するタイマーを設定できます。その場合は、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

ある条件が真になるまでスレッドをスリープさせる必要がある場合に通常行うことは、条件変数を使用することです。. スレッドはミューテックスをロックし、それを条件変数に渡してブロックします (その後、ミューテックスのロックは一時的に解放されます)。次に、待機している条件が真になると、その条件を真にしたスレッドが条件変数にシグナルを送信し、そのスレッドがウェイクアップしてミューテックスのロックを再取得し、楽しい道を進みます。ただし、注意すべきことは、条件変数が偽のウェイクアップを行う可能性があることです (また、複数のスレッドが同じ条件で待機している場合もあります)。そのため、条件が真であることを示す何らかのフラグが必要です。スレッドが条件変数からウェイクアップすると、そのフラグがチェックされ、フラグが true でない場合は条件変数で再度ブロックされます。条件変数で使用されているミューテックスは、そのフラグを保護するためにも使用されます。

D ランタイムには、 に条件変数がありcore.sync.conditionます。

このようなスタックオーバーフローの条件変数に関連する他の良い質問もあります:条件変数

さて、あなたの特定のユースケースに関しては、ウィンドウツールキットでペイントしてこれをやろうとするのは少しずれているように見えるという Idan Arye のコメントに同意する必要があります。通常、これが機能する方法は、OnPaint関数 (または特定のツールキットが呼び出すもの) をオーバーライドしてから、ウィンドウ ツールキットが関数を呼び出すことです。自分でペイントするように指示したり、条件などを待つことを心配したりする必要はありません。そのため、使用しているウィンドウ ツールキットの使用方法を誤解しているようです。

于 2013-05-15T23:44:14.053 に答える