5

2つのスレッドを持つアプリケーションがあります。

ソケットを使用してデータをキャプチャし、DataTablesを更新する最初のスレッド(メインスレッド)

2番目はDataTablesをデータベースに挿入します。

アプリケーションは正常に動作しますが、閉じると、メインスレッドはデータの読み取りを終了し、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           
        }
     }
}
4

3 に答える 3

8

両方のスレッドがバックグラウンドスレッドとしてマークされていない限り、アプリは両方のスレッドが終了するまで実行を続けます。したがって、実際に行う必要があるのは、各スレッドを個別に取得してクリーンに終了することだけです。データベースに書き込むスレッドの場合、これはプロデューサー/コンシューマーキューを使い果たし、終了するフラグをチェックすることを意味する場合があります。

ここに適切な生産者/消費者キューを示しました-ワーカーは次のようになります:

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");
    }
}
于 2009-06-28T09:42:27.760 に答える
6

「中止メソッドの呼び出し」とは、Thread.Abortを使用してスレッドを中止することを意味します。それをしないでください

あなたは事実上あなたのアプリをクラッシュさせています。モニターでこれを行うためのよりクリーンな方法はたくさんあります。

それでも、アプリがクラッシュしたときにDBに一貫性のないデータが含まれることはないはずです。そのため、 ACIDプロパティを持つDBトランザクションがあります。

非常に重要な編集 あなたは次のように述べています。パフォーマンス上の理由からトランザクションを使用せず、代わりにミューテックスを使用します。これはかなりの数のレベルで間違っています。まず、トランザクションによって特定の操作を高速化できます。たとえば、テーブルに10行を挿入してみて、トランザクション内で再試行すると、トランザクションバージョンが高速になります。次に、アプリがクラッシュした場合、DBが破損した場合はどうなりますか?アプリの複数のインスタンスが実行されているとどうなりますか?または、クエリアナライザでDBに対してレポートを実行している間ですか?

于 2009-06-28T09:44:38.363 に答える
3

ミューテックスの待機にはタイムアウトが必要です。各スレッドの外側のループは、「今すぐ閉じてください」フラグをチェックできます。シャットダウンするには、各スレッドに「今すぐ閉じてください」フラグを設定し、「結合」を使用して各スレッドが終了するのを待ちます。

于 2009-06-28T11:14:25.000 に答える