バックグラウンドを作成し、それを実行したThread
直後に呼び出すとJoin
、バックグラウンド スレッドが終了するまで現在のスレッドがブロックされるため、基本的に同期メソッドの作成に時間とメモリを浪費するだけです。現在のスレッドが UI スレッドである場合、これは明らかです。
また、Thread.Abort
スレッドを強制終了するために使用することはお勧めしません。
ほとんどの場合、メイン スレッドからのシグナルを待機する長寿命のバックグラウンド スレッドを作成することをお勧めします。これにより、ワーカー メソッドが処理できる以上のリクエストを受け取った場合に、不必要に複数のスレッドを作成することがなくなります。
これは一般的な考え方です:
// have a long lived and prosperous thread which handles jobs
private readonly Thread _backgroundWorker;
// you need a way to signal the thread to continue running
private readonly AutoResetEvent _signalNewTask;
// you need a flag indicating you want to stop (to avoid aborting the thread)
private volatile bool _keepRunning;
// and you need to pass the current job to that thread
private volatile Job _currentJob;
ループは次のようになります。
// this runs on a background thread
private void WorkerLoop()
{
Job lastJob = null; Image lastResult = null;
while (_keepRunning)
{
// use an AutoResetEvent for cross-thread signalization
_signalNewTask.WaitOne();
// make sure the app isn't ending
if (!_keepRunning)
break;
// don't bother if we already processed this job
if (lastJob == _currentJob)
continue;
// capture the job in a local variable
lastJob = _currentJob;
// long processing
lastResult = LoadImage(lastJob);
// check if this is still the last requested job
if (_keepRunning && lastJob == _currentJob)
DisplayImage(lastResult);
}
}
ジョブの実行をスケジュールするには、フィールドを設定してイベントを通知するだけです。
private void ScheduleNewJob(Job nextJob)
{
// don't waste time if not needed
if (nextJob == _currentJob)
return;
_picLoadingJobCard.Visible = true;
_currentJob = nextJob;
_signalNewTask.Set();
}
また、初期化とクリーンアップのコードを に追加する必要がありますForm
。
public SomeForm()
{
InitializeComponent();
_keepRunning = true;
_signalNewTask = new AutoResetEvent(false);
_backgroundWorker = new Thread(WorkerLoop);
_backgroundWorker.IsBackground = true;
_backgroundWorker.Priority = ThreadPriority.BelowNormal;
_backgroundWorker.Start();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
// set the running flag to false and signal the thread
// to wake it up
_keepRunning = false;
_signalNewTask.Set();
// this will lock very shortly because the background
// thread breaks when the flag is set
_backgroundWorker.Join();
base.OnFormClosed(e);
}
そして、DisplayImage
(または何でも)バックグラウンド スレッドから呼び出されるため、次のように呼び出して UI スレッドでスケジュールする必要がありますInvoke
。
private void DisplayImage(Image result)
{
if (this.InvokeRequired)
{
Invoke(new Action<Image>(DisplayImage), result);
return;
}
_picLoadingJobCard.Visible = false;
_picJobCard.Image = result;
}