コードの実行中にフォームがフリーズする(10秒程度)ため、GUIとは異なるスレッドで実行する必要があるコードが少しあります。
これまでに新しいスレッドを作成したことがないと仮定します。これをC#で実行し、.NET Framework 2.0以降を使用する方法の簡単な基本例は何ですか?
コードの実行中にフォームがフリーズする(10秒程度)ため、GUIとは異なるスレッドで実行する必要があるコードが少しあります。
これまでに新しいスレッドを作成したことがないと仮定します。これをC#で実行し、.NET Framework 2.0以降を使用する方法の簡単な基本例は何ですか?
回答:
独自のスレッドを作成する場合、これは簡単です。
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
Console.WriteLine("Hello, world");
}).Start();
IsBackground
trueに設定する場合は注意してください。それはおそらくあなたが思っていることをしていません。これは、すべてのフォアグラウンドスレッドが終了したときにスレッドを強制終了するか、またはスレッドがアプリケーションを存続させるかを構成します。実行中にスレッドを終了させたくない場合はIsBackground
、trueに設定しないでください。
BackgroundWorker
あなたにとって最良の選択のようです。
これが私の最小限の例です。ボタンをクリックすると、バックグラウンドワーカーがバックグラウンドスレッドでの作業を開始し、その進行状況も同時に報告します。作業完了後にも報告します。
using System.ComponentModel;
...
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
// this allows our worker to report progress during work
bw.WorkerReportsProgress = true;
// what to do in the background thread
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
// do some simple processing for 10 seconds
for (int i = 1; i <= 10; i++)
{
// report the progress in percent
b.ReportProgress(i * 10);
Thread.Sleep(1000);
}
});
// what to do when progress changed (update the progress bar for example)
bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
});
// what to do when worker completes its task (notify the user)
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
label1.Text = "Finished!";
});
bw.RunWorkerAsync();
}
注意:
ProgressChanged
または
RunWorkerCompleted
ハンドラ内でGUIを更新しても安全
です。ただし、からGUIを更新すると、DoWork
が発生し
InvalidOperationException
ます。ThreadPool.QueueUserWorkItemは何か、簡単なため、かなり理想的です。唯一の注意点は、他のスレッドからコントロールにアクセスすることです。
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
DoSomethingThatDoesntInvolveAControl();
}, null);
速くて汚いですが、うまくいきます:
上部で使用:
using System.Threading;
簡単なコード:
static void Main( string[] args )
{
Thread t = new Thread( NewThread );
t.Start();
}
static void NewThread()
{
//code goes here
}
私はこれを例の新しいコンソールアプリケーションに投げ込みました
ここに別のオプションがあります:
Task.Run(()=>{
//Here is a new thread
});
BackgroundWorkerクラスを使用してみてください。何を実行するか、作業が終了したときに通知を受けるようにデリゲートを与えます。リンク先のMSDNページに例があります。
そのコードを関数(GUIと同じスレッドで実行できないコード)に入れ、そのコードの実行をトリガーするには、以下を入力します。
Thread myThread= new Thread(nameOfFunction);
workerThread.Start();
スレッドオブジェクトで開始関数を呼び出すと、新しいスレッドで関数呼び出しが実行されます。
nameOfFunction
、現在のGUIスレッドではなく、バックグラウンドで実行されます。IsBackground
プロパティは、スレッドが生きているのかいないアプリケーションを維持するかどうかを決定します。msdn.microsoft.com/en-us/library/...
ここでは、progressBarでスレッドを使用する方法を説明します。これは、スレッドがどのように機能するかを理解するためのものであり、フォームには3つのProgressBarと4つのボタンがあります。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread t, t2, t3;
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
t = new Thread(birinicBar); //evry thread workes with a new progressBar
t2 = new Thread(ikinciBar);
t3 = new Thread(ucuncuBar);
}
public void birinicBar() //to make progressBar work
{
for (int i = 0; i < 100; i++) {
progressBar1.Value++;
Thread.Sleep(100); // this progressBar gonna work faster
}
}
public void ikinciBar()
{
for (int i = 0; i < 100; i++)
{
progressBar2.Value++;
Thread.Sleep(200);
}
}
public void ucuncuBar()
{
for (int i = 0; i < 100; i++)
{
progressBar3.Value++;
Thread.Sleep(300);
}
}
private void button1_Click(object sender, EventArgs e) //that button to start the threads
{
t.Start();
t2.Start(); t3.Start();
}
private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
{
t.Suspend();
t2.Suspend();
t3.Suspend();
}
private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
{
t.Resume();
t2.Resume();
t3.Resume();
}
private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
{
t.Abort();
t2.Abort();
t3.Abort();
}
}
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
Charles(上記)のコードは正しくありません。スピンして完了するまで待つ必要はありません。EndInvokeは、WaitHandleが通知されるまでブロックします。
完了するまでブロックしたい場合は、単に
nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));
または代わりに
ar.AsyncWaitHandle.WaitOne();
しかし、ブロックした場合にanyc呼び出しを発行する意味は何ですか?同期呼び出しを使用することもできます。より良い賭けは、クリーンアップのためにラムダをブロックして渡さないことです:
nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);
覚えておくべきことの1つは、EndInvokeを呼び出す必要があることです。ほとんどの非同期実装がEndInvokeでウェイトハンドルを解放するため、多くの人がこれを忘れて、WaitHandleをリークすることになります。
生のThreadオブジェクトを使用する場合は、IsBackgroundを少なくともtrueに設定する必要があり、Threading Apartmentモデル(おそらくSTA)も設定する必要があります。
public static void DoWork()
{
// do some work
}
public static void StartWorker()
{
Thread worker = new Thread(DoWork);
worker.IsBackground = true;
worker.SetApartmentState(System.Threading.ApartmentState.STA);
worker.Start()
}
UIの操作が必要な場合は、BackgroundWorkerクラスをお勧めします。
デリゲートとスレッドプールを使用する別のオプション...
'GetEnergyUsage'は、DateTimeと別のDateTimeを入力引数として取り、Int ...
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
int usageCnt = nrgDel.Invoke(lastRunTime, procDT, null, null);
ますか?とにかく、現在のスレッドをスリープ状態で一時停止しているようです... GUIスレッドで呼び出すと、GUIがフリーズしても何も役に立たないと思いました
.Netで個別のスレッドを実行するには多くの方法があり、それぞれに異なる動作があります。GUIの終了後もスレッドを実行し続ける必要がありますか?スレッドとGUIの間で情報を受け渡す必要がありますか?スレッドはGUIを更新する必要がありますか?スレッドは1つのタスクを実行して終了する必要がありますか、それとも実行を継続する必要がありますか?これらの質問に対する答えは、使用する方法を教えてくれます。
コードプロジェクトのWebサイトには、さまざまなメソッドについて説明し、サンプルコードを提供する優れた非同期メソッドの記事があります。
この記事は、非同期/待機パターンとタスク並列ライブラリが.NETに導入される前に作成されたことに注意してください。
他のスレッドからGUI固有のものへのアクセスには非常に注意する必要があります(多くのGUIツールキットで一般的です)。処理スレッドからGUIで何かを更新したい場合は、WinFormsに役立つと思うこの回答を確認してください。WPFについては、これを参照してください(他のスレッドから機能するようにUpdateProgress()メソッドでコンポーネントにタッチする方法を示していますが、実際には、Dispathcer CheckAccess()
をBeginInvoke
介して実行する前にそれが行われていないので、CheckAccessを参照して検索してください)
スレッドに関する.NET固有の本を探していたところ、これが見つかりました(無料でダウンロード可能)。詳細については、http://www.albahari.com/threading/を参照してください。
最初の20ページで新しいスレッドとして実行を開始するために必要なものが見つかり、さらに多くのスレッドが含まれていると思います(スレッド化に厳密に固有のGUI固有のスニペットについてはわかりません)。この作品を読んでいるため、コミュニティがこの作品についてどう思っているかを聞いていただければ幸いです。今のところ、(スレッド化のための.NET固有のメソッドとタイプを示すために)私にはかなり見栄えがしました また、私が本当に感謝する.NET 2.0(および古代1.1ではない)についても説明します。
Jeff RichterのPower Threading Library、特にIAsyncEnumeratorを確認することをお勧めします。チャーリーカルバートのブログで、リヒターが概要を説明しているビデオをご覧ください。
非同期プログラミングタスクのコーディングが容易になるので、名前を間違えないでください。