2012-01-05 6 views
0

ChangeText()&という名前の2つの関数ChangeColor()は、最初にChangeTextという関数を呼び出すことで、大量のデータをメモリにロードしますが、時間がかかるため、非同期に実行します。もう1つはChangeColorと呼ばれ、データのロード時にボタンの色が変わるため、ChangeTextとChangeColorの2つの関数を実行する順序があります。これら二つの機能はまだで実行しているだろうことを、私はこの2つの関数を同期するためにEventWaitHandleを使用する予定EventWaitHandleはなぜ機能しませんか?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ThreadSynchorous 
{ 
    public class AsyncInvoke 
    { 
     public void BeginAsync(Func<bool> MyFunction) 
     { 
      Func<bool> func = new Func<bool>(MyFunction); 
      IAsyncResult iar = func.BeginInvoke(new AsyncCallback(EndAsync), func); 
     } 

     public void EndAsync(IAsyncResult iar) 
     { 
      Func<bool> func = (Func<bool>)iar.AsyncState; 
      func.EndInvoke(iar); 
     } 
    } 
} 

が、結果は次のとおりです。ここ

using System; 
using System.Text; 
using System.Windows; 
using System.Windows.Media; 
using System.Threading; 
using System.IO; 

namespace ThreadSynchorous 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
     InitializeComponent(); 
     asyncInvoke = new AsyncInvoke(); 
    } 
    AsyncInvoke asyncInvoke; 
    EventWaitHandle waitMeHandle = new EventWaitHandle(false,EventResetMode.ManualReset); 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
     { 
      asyncInvoke.BeginAsync(ChangeText); 
     }), null); 

     ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
     { 
      asyncInvoke.BeginAsync(ChangeColor); 
     }), null); 

     label1.Content += " \r\n-------------------------\r\n"; 
    } 

    private bool ChangeText() 
    { 
     waitMeHandle.Reset(); 
     this.button1.Dispatcher.Invoke(new Func<bool>(delegate() 
     { 
      string filename = @"C:\EXO.txt"; 
      using (StreamReader sr = new StreamReader(filename, Encoding.Default)) 
      { 
       string result; 
       while ((result = sr.ReadLine()) != null) 
       { 
        //here perform action 
       } 
      } 

      label1.Dispatcher.Invoke(new Func<bool>(delegate 
      { 
       label1.Content += "Loading finish!(Thread.CurrentThreadName="+Thread.CurrentThread.ManagedThreadId.ToString()+") "; 
       waitMeHandle.Set(); 
       return true; 
      })); 
      waitMeHandle.Set(); 
      return true; 
     })); 
     waitMeHandle.Set(); 
     return true; 
    } 

    private bool ChangeColor() 
    { 
     waitMeHandle.WaitOne(); 
     this.button1.Dispatcher.Invoke(new Func<bool>(delegate() 
     { 
      this.button1.Background = Brushes.Red; 

      label1.Dispatcher.Invoke(new Func<bool>(delegate() 
      { 
       label1.Content += "Coloring finish!(Thread.CurrentThreadName="+Thread.CurrentThread.ManagedThreadId+") "; 
       return true; 
      })); 

      return true; 
     })); 
     return true; 
    } 
} 
} 

AsyncInvokeのクラスがされています。ここに私のコードです混乱の順序:ChangeText()関数を先に使うこともあります。時にはChangeColor()を先に使うこともあります。私はちょっと混乱している。

そしてまた、私はこの二つの機能を起動するためのThreadPoolを使用しますが、なぜ私は以下のように同じスレッドIDました!:
ロード仕上げ(Thread.CurrentThreadName = 10)着色仕上げを(Thread.CurrentThreadName = 10)

スレッドプールを使用しているため、Thread.CurrentThreadNameが異なると私は考えました。どうして?あなたの答えのためのthx。

答えて

0
public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 
     asyncInvoke = new AsyncInvoke(); 
    } 
    AsyncInvoke asyncInvoke; 
    EventWaitHandle waitMeHandle = new EventWaitHandle(false, EventResetMode.ManualReset); 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
     { 
      asyncInvoke.BeginAsync(ChangeText); 
     }), null); 

     ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
     { 
      asyncInvoke.BeginAsync(ChangeColor); 
     }), null); 

     label1.Content += " \r\n-------------------------\r\n"; 
    } 

    private bool ChangeText() 
    { 
     Debug.WriteLine("ChangeText");   

     //do your time-consuming operation here, controls' delegated are for UI updates only 

     this.button1.Dispatcher.Invoke((Action)(()=> 
     { 
      Thread.Sleep(2000); 
      Debug.WriteLine("Button invoker"); 
      //update button here 


      //what was bool return type for? 
      label1.Dispatcher.Invoke((Action)(() => 
      { 
       label1.Content += "Loading finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId.ToString() + ") "; 
       waitMeHandle.Set(); 
      })); 

     })); 


     //waitMeHandle.Set(); - here's your guilty - button delegate runs asynchrounously so you had absolutely no guarantee that it's done as your app reach this line 
     return true; 
    } 

    private bool ChangeColor() 
    { 
     waitMeHandle.WaitOne(); 
     Debug.WriteLine("ChangeColor"); 
     this.button1.Dispatcher.Invoke((Action)(() => 
     { 
      this.button1.Background = Brushes.Red; 

      label1.Dispatcher.Invoke((Action)(() => 
      { 
       label1.Content += "Coloring finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId + ") "; 
       waitMeHandle.Reset(); //you've consumed your event here so this is the place to reset it 
      })); 
     })); 
     return true; 
    } 
} 

上記のコードスニペットをご覧ください。少し説明があります。もちろん、ラベルスレッドをUIスレッドにディスパッチするため、スレッド名が同じになっています。これは、最初に行ったような長い操作を行うべきではないという主な理由です。

+0

こんにちはgrzegorz_p、実際これはサンプルですが、ChangeColor関数は多くのデータを取り出して古いtxtファイルと比較し、古いものと同じデータを表示します。だからここで私はちょうど別々に機能を実行する。あなたの返信のためのthx :) – CharlieShi

+0

私は少し調査をしたし、我々は有罪を持っているようだ:) –

+0

私はあなたが何を意味するか正確には分かりません。私はThreadPool.QueueUserWorkItem(o => ChangeText())を使うべきだと思います。 ThreadPool.QueueUserWorkItem(o => ChangeColor());代わりに。 – CharlieShi

0

あなたの質問(私はコード上に他の可能性のある問題が表示されます)を構築するにはイベントハンドラを設定し、Change_TextメソッドのwaitMeHandle.Reset();を削除しようとします。

2つのプロセスを同時に起動するので、最初にChange_Textが実行されることを確認することはできません。

+0

SoMosの返答のためのThxは、waitMeHandle.Reset()を削除した後です。それでも正常に動作しません。 2つのプロセスを並行して実行しても、なぜ私はまだEventWaitHandleを使用して制御できないのですか?これには良い解決策がありますか?ミューテックスやジョインなどを使うのと同じですか?起こりうる問題を指摘しますか? thx :) – CharlieShi

0

名前に関する質問実行中のスレッドは次のようになります。

Dispatcher.Invokeを呼び出すと、指定されたデリゲートはDispatcherが関連付けられているスレッドで実行されます。おそらくUIスレッド。

MSDN上の発言のセクションを参照してください:

WPFでは、DispatcherObjectにを作成したスレッドだけがそのオブジェクトにアクセスすることができます。たとえば、メインUIスレッドから分離されたバックグラウンドスレッドは、UIスレッドで作成されたボタンの内容を更新できません。バックグラウンドスレッドがButtonのContentプロパティにアクセスするためには、バックグラウンドスレッドはUIスレッドに関連付けられたDispatcherに作業を委任する必要があります。これは、InvokeまたはBeginInvokeのいずれかを使用して行います。

次に、あなたは過酷なことをしています。 ThreadPool.QueueUserWorkItemに電話すると、デリゲートがThreadPoolスレッド上で実行するようにスケジュールしています。コード内で、ThreadPoolスレッドで実行されるメソッド内でFunc<T>.BeginInvokeを呼び出すと、再度、デリゲートがThreadPoolスレッドで実行されるようにスケジュールされます。だから、このようにコードを変更:

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     ThreadPool.QueueUserWorkItem(o => ChangeText()); 

     ThreadPool.QueueUserWorkItem(o => ChangeColor()); 

     label1.Content += " \r\n-------------------------\r\n"; 
    } 

はThreadPoolのスレッドでChangeTextChangeColorを実行するのに十分です。

+0

oh ... thx afrischke、私はthreadnameが同じ理由を知る必要があります。私はテストを行うだけで、MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());と書いてください。 ChangeText関数とChangeColor関数のintの前に、ThreadIdが7と12であることが示されます。 – CharlieShi

+0

あなたの助けにthx、今すべての問題が解決されました。あなたの仕事に非常に感謝します。 :) – CharlieShi

関連する問題