0

C# 4.0 でコミック リーダーを実装していますが、実装したいくつかのプロセスのために、ある画像から次の画像への参照に時間がかかります。

したがって、バックグラウンド スレッドが画像を処理している間に UI スレッドが最初に未処理の画像を表示し、後で未処理の画像を置き換えるように実装しました。

すべて正常に動作しますが、一部のユーザーは狂ったように次の画像を継続的にクリックすることを好むため、バックグラウンド ワーカーがそれらすべてのクリックを処理し、すべての画像を表示します。

私が望むこと: ユーザーが複数回クリックした場合、バックグラウンド ワーカーが最後のスレッドのみを処理するようにします。

私がやったこと:現在、アクティブなスレッドの数をチェックする関数を実装しました。アクティブなスレッドが1より大きい場合、バックグラウンドスレッドは処理せずに前の画像を返します(未処理の画像がインデックスが 1 つ先になります)

アイデアがあれば、初心者のように説明してください!

private void button4_Click(object sender, EventArgs e)
{

    Bitmap b = new Bitmap(this.CurrImage);

           if (!shutdown)
          {
            process_updateThread = new Thread(new ThreadStart(process_update));
            process_updateThread.Start();
          }

    pictureBox1.Image = b; //image will be replaced by worker thread image 
    pictureBox1.Location = ImageEdit.CalculateLocationImage(b);
    SetBackColor(b);
    ShowPageCount();
    updateNavButtons(); 
}


void StopThread()
{
    if(((IEnumerable)System.Diagnostics.Process.GetCurrentProcess().Threads).OfType<System.Diagnostics.ProcessThread>()
        .Where(t => t.ThreadState == System.Diagnostics.ThreadState.Running).Count() > 1) 
    shutdown = true;
    else shutdown = false;
}
4

2 に答える 2

0

長時間実行されているプロセスが process_update であると想定しています。

次の更新を実行する前に、実行中のすべての process_updates を停止する必要があります。しかし、それを行うためにブール変数を使用しないでください!!! 同期オブジェクトを使用する必要があります。最も可能性が高いのは、ManualResetEvent です。

アップデート:

この非常に単純な例から、マルチスレッドとスレッド管理のアイデアを得ることができます

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;


namespace WindowsFormsExamples
{
    public partial class OnlyOneThread : Form
    {
        List<ManualResetEvent> threadStopEvents;    //This will hold stop events for running threads

        public OnlyOneThread()
        {
            InitializeComponent();
            threadStopEvents = new List<ManualResetEvent>();
        }

        private void runThreadBtn_Click(object sender, EventArgs e)
        {
            ManualResetEvent evt = new ManualResetEvent(false);
            ParameterizedThreadStart ts = new ParameterizedThreadStart(this.ThreadFunc);
            Thread t = new Thread(ts);
            t.Start(evt);
        }

        private delegate void UptadeThreadCountDelegate();   //This delegate is used by Invoke method
        private void UpdateThreadCount()
        {
            threadcountLbl.Text = threadStopEvents.Count.ToString();
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            //We must stop threads if they are still running

            lock (threadStopEvents)  // locking prevents simultaneous list access
            {
                foreach (ManualResetEvent evt in threadStopEvents)
                {
                    evt.Set(); //signal all events
                }
            }
        }


        //This is thread function
        private void ThreadFunc(Object obj)
        {
            ManualResetEvent stopEvent = obj as ManualResetEvent; //cast an object that was passed by Thread.Start()

            lock (threadStopEvents) // locking prevents simultaneous list access
            {
                foreach (ManualResetEvent evt in threadStopEvents)
                {
                    evt.Set(); //signal all events for all other threads to stop
                }

                threadStopEvents.Add(stopEvent);  //Put our event on list
            }

            if (this.IsHandleCreated) // This is necessary for invocation
                this.Invoke(new UptadeThreadCountDelegate(this.UpdateThreadCount));  //Invoke counter update

            for (int i = 0; i < 60; i++) // this will run about 1 minute
            {
                if (stopEvent.WaitOne(0)) // Tests stopEvent and continues
                {
                    //Stop signaled!!! exit!
                    break;
                }

                Thread.Sleep(1000); //Sleep 1 second
            }
            lock (threadStopEvents) // locking prevents simultaneous list access
            {
                threadStopEvents.Remove(stopEvent); //remove stop event from list
            }
            if (this.IsHandleCreated) // This is necessary for invocation
                this.Invoke(new UptadeThreadCountDelegate(this.UpdateThreadCount));  //Invoke counter update
        }
    }
}

この例を実行する場合は、WindowsForms プロジェクトを作成し、フォームにボタンとラベルを追加してから、このコードを使用してそれらのコントロールにバインドする必要があります。forms メソッドの呼び出しに注意してください。これは、GUI 以外のスレッドから実行する場合に必要です。

于 2013-02-21T07:16:43.990 に答える
0

この問題の簡単な解決策がわかりません... マルチスレッドは決して簡単ではありません。個人的には、次のことを提案します (生産者/消費者の状況の一種の逸脱):

  • 最初に、現在レンダリングされているイメージを示す一般的なカウンターがあります (ボタンが押されるたびにインクリメントされる単純な int にすることができます)。

適切にロックされ、次のメソッドを持つ ImageMonitor:

  • レンダリングする画像を追加します(現在のカウンターを使用)->これは、ボタンが押されるたびに発生します
  • レンダリングする必要がある画像を取得します (画像のカウンターを含む)
  • レンダリング イメージを処理する

ここで、継続的に動作するバックグラウンド スレッドが必要です。このスレッドはループし、反復ごとに処理する最新の画像を ImageMonitor でチェックし、画像を処理して ImageMonitor (カウンターを含む) に返します。

ImageMonitor は、レンダリングされた画像をバックグラウンド レンダラーから取得すると、画像に正しいカウンター値があるかどうかを確認できます。正しい場合は、現在の画像をレンダリングされた画像と交換できます。

この解決策は明らかに少し複雑です。ただし、動作するはずです。他の(より簡単な)ソリューションに興味があります。

幸運を

于 2013-02-21T07:18:17.877 に答える