マルチスレッド アプリケーションを正常に終了しますか?
-
20-08-2019 - |
質問
2 つのスレッドを持つアプリケーションがあります。
ソケットを使用してデータをキャプチャし、DataTable を更新する最初のスレッド (メインスレッド)
2 つ目は、DataTable をデータベースに挿入します。
アプリケーションは正常に動作しますが、終了すると、メインスレッドがデータの読み取りを終了し、2 番目のスレッドで Abort メソッドを呼び出します。このメソッドはデータベースに挿入している可能性があり、これによりデータの不整合が発生します。
現在、「挿入中の中断」を克服するために次の解決策を使用しています。
編集:強力な回答の後、コードを変更しました
void MainThread()
{
while(Read())
{
//Read Data through socket
try
{
//Wait on Mutex1
//Update Tables
}
finally
{
//Release Mutex1
}
}
_isrunning = false;
_secondThread.Join();
}
void SecondThread()
{
while(_isrunning)
{
try
{
//Wait on Mutex1
//Insert Tables into Database using transactions
}
finally
{
//Release Mutex1
}
}
}
解決
「中止メソッドの呼び出し」とは、Thread.Abort を使用してスレッドを中止することを意味すると仮定します。 そんなことはしないでください.
実質的にアプリをクラッシュさせていることになります。モニターを使用してこれを行うためのよりクリーンな方法がたくさんあります。
それにもかかわらず、アプリがクラッシュしたときに DB 内で一貫性のないデータが取得されるべきではありません。そのため、 酸 プロパティ。
非常に重要な編集あなたが言った:パフォーマンス上の理由からトランザクションは使用せず、代わりにミューテックスを使用します。これは 間違っている かなりのレベルで。まず、トランザクションによって特定の操作が高速化されます。たとえば、テーブルに 10 行を挿入して、トランザクション内で再試行すると、トランザクション バージョンが高速になります。次に、アプリがクラッシュした場合、DB が破損した場合はどうなりますか?アプリの複数のインスタンスが実行されている場合はどうなりますか?それともクエリ アナライザーで DB に対してレポートを実行している間でしょうか?
他のヒント
限り、両方のスレッドがバックグラウンドスレッドとしてマークされていないとして、アプリは両方のスレッドが終了するまで実行し続けます。だから、本当に、あなたがする必要があるすべては正常に終了するために個別に各スレッドを取得することです。データベースへの書き込みスレッドの場合、これは、プロデューサ/コンシューマキューを排出し、終了フラグをチェックする意味してもよい。
私はここを、適切なプロデューサ/コンシューマキューのを示した - 労働者だけになります:
void WriterLoop() {
SomeWorkItem item; // could be a `DataTable` or similar
while(queue.TryDequeue(out item)) {
// process item
}
// queue is empty and has been closed; all done, so exit...
}
<時間>
ここでSizeQueue<>
に基づく完全な例だ - プロセスがリーダーになるまで出ないことに注意のとのライターがきれいに終了しています。あなたは(すなわち、あなたはすぐに終了し、保留中の仕事を忘れたい)キューを排出したくない場合は、罰金 - どこかに余分な(揮発性)フラグを追加
static class Program {
static void Write(object message) {
Console.WriteLine(Thread.CurrentThread.Name + ": " + message);
}
static void Main() {
Thread.CurrentThread.Name = "Reader";
Thread writer = new Thread(WriterLoop);
writer.Name = "Writer";
var queue = new SizeQueue<int>(100);
writer.Start(queue);
// reader loop - note this can run parallel
// to the writer
for (int i = 0; i < 100; i++) {
if (i % 10 == 9) Write(i);
queue.Enqueue(i);
Thread.Sleep(5); // pretend it takes time
}
queue.Close();
Write("exiting");
}
static void WriterLoop(object state) {
var queue = (SizeQueue<int>)state;
int i;
while (queue.TryDequeue(out i)) {
if(i%10==9) Write(i);
Thread.Sleep(10); // pretend it takes time
}
Write("exiting");
}
}
あなたのミューテックスの待ちがタイムアウトを関与させるべきです。各スレッドの外側のループは「今閉じてください」フラグをチェックすることができます。設定し、シャットダウンするには、各スレッドが終了するのを待つために「参加する」を使用し、各スレッドのためのフラグ「を今すぐ閉じてください」。