2011-07-17 11 views
2

私は、テキストファイルから読み込んだデータをディレクトリからデータベースにインポートするアプリケーションを持っています。ユーザーがインポートボタンをクリックしてデータのインポートを開始できるUIがあり、ユーザーがそのボタンを再度クリックすると、そのファイルのデータのインポートを停止したいと考えました。私はこれを可能にするためにスレッドを使い始めたので、データがインポートされている間はUIをフリーズしませんでした。しかし、私はいくつかの問題があります。ユーザーがインポートを停止した後にthread.Abort()を使用してスレッドを終了しましたが、ユーザーが再度インポートをクリックすると、必要なテキストファイルの先頭に読み込みを開始するため、重複したデータがデータベースに追加されます。 ManualResetEventsとThread.Join()を使用してインポートをトリガーするように指示されていますが、どのように動作するのか混乱しています。基本的にやろうとしているイムのために眠るそれ以外のデータをインポートするが、その後がある場合、ループして読み取られるすべてのファイルがあるかどうかをチェックトレッドを保つために何であるかC#手動リセットイベントによるスレッディング

public ManualResetEvent event1 = new ManualResetEvent(false); 
    public Thread workerThread; 


    public Form1 
    { 
     InitializeComponent(); 
    } 

    private void importButton_Click(object sender, EventArgs e) 
    { 
     if(importButton.Text == "Begin Import") 
     { 
      importButton.Text = "Stop Import"; 
      //runs a service that begins reading and importing data and writing to 
      //a "console" box. 
      Service service = new Service(consoleBox); 
      //run the new thread to begin importing data 
      workerThread = new Thread(service.importData); 
      workerThread.Start(); 

     } 
     else 
     { 
      importButton.Text = "Begin Import"; 
      event1.Set(); 
      while(!event1.WaitOne(TimeSpan.FromSeconds(4))) 
      { //imports data for 30 more text files 
        service.importData(30); 
        workerThread.Join(); 

      } 


     } 
    } 

:今私のコードは次のようになります4秒。私はこのためにスレッドタイマーを使用する必要がありますか?私は何をするのか分からない。

答えて

0

スレッドの代わりにインポートプロセスを実行するためのタイマーを使用し、回避する必要があるthread.Abort()というユーザーの停止の要求があるかどうかを確認する変数を定義します。

このコードでは、System.Timers.Timerを使用してください。フラグAutoResetをfalseに設定すると、ユーザーが停止を要求しない場合にのみデータをインポートできます。

private System.Timers.Timer _importTimer = new System.Timers.Timer(); 
private volatile bool _requestStopImport = false; 

public Form1() 
{ 
    InitializeComponent(); 

    _importTimer.Interval = 4000;//4 seconds 
    _importTimer.AutoReset = false;//not automatically raise elapse event each time interval elapsed, only if we don't want to stop. 
    _importTimer.Elapsed += OnImportTimerElapced; 
} 

private void importButton_Click(object sender, EventArgs e) 
{ 
    if (importButton.Text == "Begin Import") 
    { 
     importButton.Text = "Stop Import"; 
     StartImport(); 
    } 
    else 
    { 
     importButton.Text = "Begin Import"; 
     StopImport(); 
    } 
} 

private void OnImportTimerElapced(object sender, System.Timers.TimerEventArgs e) 
{ 
    //runs a service that begins reading and importing data and writing to 
    //a "console" box. 
    Service service = new Service(consoleBox);//or maybe this would be a class level variable 
    service.importData(); 

    if (!_requestStopImport) 
    { 
     _importTimer.Start(); 
    } 
} 

private void StartImport() 
{ 
    _requestStopImport = false; 
    _importTimer.Start(); 
} 

private void StopImport() 
{ 
    _requestStopImport = true; 
    _importTimer.Stop(); 
} 

ここでは、ManualResetEventを使用する必要はありません。ただし、コードが完了したときにを通知したい場合は、AutoResetEventを使用するか、より詳細な例チェックthisのイベントを呼び出すことができます。

1

Thread.JoinまたはManualResetEvent.WaitOneを呼び出すことによって、UIスレッドをブロックしないでください。これはあなたが防止しようとしていたものとまったく同じです。 UIをフリーズします。代わりに、状態を最初にtrueに設定してMREを作成する必要があります。 importDataメソッドでは、定期的にWaitOneを呼び出して、インポートが進むか(イベントが通知されたとき)、一時停止するか(イベントが通知されないか)を確認する必要があります。

メソッド内でWaitOneを呼び出す方法の概略を示します。明らかに、特定の実装に合わせて調整する必要があります。

private void importData() 
{ 
    foreach (string filePath in GetFilesInSomeDirectory()) 
    { 
    event1.WaitOne(); // Block when the MRE is unsignaled. 
    } 
} 

は、その後、あなたのimportButton.Clickイベントハンドラから、あなたはそれを再開するためにインポート操作やevent1.Setを一時停止するevent1.Resetを呼び出すことができます。

また、Thread.Abortにかけてもかまいません。 AppDomainの状態を破壊するのを避けるために特別な、ほぼ不可能な注意を払わない限り、通常はより多くの問題につながります。

関連する問題