2012-03-08 14 views
3

基本的には、Webページにいくつかのhtmlが現れるまで待つ必要があります。私は私のためにビジー待機に次のコードを作成しました:ビジー待機スレッドwith

public void ExecuteBusyWaitThreads() 
    { 

     foreach (Canidate canidate in allCanidates) 
     { 
      Thread newThread = new Thread(delegate() 
      { 
       BusyWait(canidate); 
      }); 

      newThread.Start(); 
     } 
    } 

    public bool BusyWait(Canidate canidate) 
    { 
     //hit that url, and wait for the claim all button to appear 
     string page = null; 
     while (found == false) 
     { 
      HttpWebRequest request = Canidate.GetHTTPRequest(canidate.URL); 
      //make sure we add the authentication cookes to the request 
      request = Canidate.AddCookiesToRequest(request, canidate.GetCookies()); 
      page = new Canidate().GetPage(request); 
      if (page.ToLower().Contains("claim all")) 
      { 
       found = true; 
       NotifyAllThreads(); 
      } 
     } 
     return true; 
    } 

私は8 canidatesを持っていたのであれば、それは、ウェブページに表示するclaim allを探しているそれぞれの8つのスレッドをオフに産卵でしょう。 foundはグローバル変数です。スレッドの1つがclaim allを見つけたら、それらはすべて保守すべきです。

私はこのアプローチに関するいくつかの質問があります。まず、良いアプローチです。第2に、各スレッドはビジー待機機能のそれ自身の「コピー」を得るでしょう。つまり、あるスレッドが別のスレッドを優先してその関数内のデータを変更するか、関数内で宣言された変数のコピーをそれぞれ得ることができます。これらの関数の両方が同じオブジェクトの内部にあることに注意してください。

+1

有効な技術的な質問ですが、ポーカーやオークションで不正行為を試みるように見えます。 –

答えて

2

第二に、各スレッドは、それが任意の変数は内部のローカルであることを意味ように、各スレッドは、それ自身のスタックスペースで機能を実行しますビジーウェイト機能の独自の「コピー」

を取得しますあなたの関数はそれが実行されているスレッドに属します。関数内で変数foundなどのグローバル変数が変更されている場合は、同期メカニズムを設定して複数のスレッドからのアクセスが同時に発生しないようにする必要があります。あなたは今までに想像したくない恐ろしいものをたくさん!

2

すべてのスレッドはローカル変数のコピーを取得します(この場合はstring pageのみ)。

あなたの共有found変数は、これはThread.Sleep()への呼び出しは、いくつかの良いを行う可能性がありますまれな状況である揮発性

として宣言する必要があります。同じサイトへの呼び出しの間に少し息をする。

+0

私はそれをやっていると思っていました。しかし、Thread.Sleep()を追加することのメリットを詳しく説明できますか?私のアプリケーションは実際に他の人と競合しています。最初に「すべてを主張する」ボタンを検出することが非常に重要です。 Thread.Sleep()を追加したり、この状況を傷つけたりしますか?ありがとう – user489041

+0

短いSleep()は残りのシステムを解放し、8つのタスクをより均等に処理します。しかし、最後のmsまで競争力を持つために、スリープ()しないでください。 –

2

各スレッドは、変数の独自のコピーで実行されます。

しかし、私は自分のアピールを見事に修正します。見つかった変数を使用するのはスレッドセーフではありません。一度に複数のスレッドが変更される可能性があります。あるスレッドが他のスレッドがそれを読み込んでいる間にもう一方のスレッドがそれを読み込んでいる可能性も非常に高いです。 [lock][1]はこれを避けることができます。

この問題を解決するより良い方法は、EventWaitHandleを使用することです。あなたは本当にロックを心配する必要はありませんし、あなたはスリープやタイムアウトで構築することができますので、 'claim-all'が表示されない場合、スレッドはあなたが望むより長く実行されません。

internal class ExampleOnExecute 
{ 
    private static EventWaitHandle _stopEvent; 

    public static EventWaitHandle StopEvent 
    { 
     get { return _stopEvent ?? (_stopEvent = new EventWaitHandle(false, EventResetMode.ManualReset)); } 
    } 

    public static void SpinOffThreads(IEnumerable<object> someCollection) 
    { 
     foreach(var item in someCollection) 
     { 
      // You probably do not want to manualy create a thread since these ideally would be small workers 
      // and action BeingInvoke runs in the ThreadPool 
      Action<object> process = BusyWait; 

      process.BeginInvoke(item, null, null); 
     } 
    } 

    private static void BusyWait(object obj) 
    { 
     // You can wait for however long you like or 0 is not waiting at all 
     const int sleepAmount = 1; 

     //  Blocks the current thread until the current instance receives a signal, using 
     //  a System.TimeSpan to specify the time interval. 
     // 
     // Parameters: 
     // timeout: 
     //  A System.TimeSpan that represents the number of milliseconds to wait, or 
     //  a System.TimeSpan that represents -1 milliseconds to wait indefinitely. 
     // 
     // Returns: 
     //  true if the current instance receives a signal; otherwise, false. 
     while (!StopEvent.WaitOne(TimeSpan.FromMilliseconds(sleepAmount))) 
     { 
      // Do you work here 
      var foundIt = DidIFindIt(); 

      if (foundIt) 
      { 
       // Signal all threads now to stop working we found it. 
       StopEvent.Set(); 
      } 
     } 
    } 

    private static bool DidIFindIt() 
    { 
     return true; 
    } 
} 

Herethreadingに優れたFREE本です。

5

私があなたの質問に答える前に、あなたが悪い行為をしたことを指摘しなければなりません。closing over the loop variable

まず、良いアプローチです。

いいえ、実際はありません。スレッドを任意に作成するのは良い考えではありません。スレッドプーリング技術を使用する方が良いです。これはThreadPool.QueueUserWorkItemまたはTaskクラスで行うことができます。

第2に、各スレッドはビジー待機機能の独自の「コピー」を取得します。 つまり、あるスレッドが別のスレッドをプリエンプトして、その関数のデータを に変更するか、関数内で と宣言された変数のコピーをそれぞれ取得できますか?

BusyWaitの実行中の各インスタンスは、すべてのローカル変数(すなわち。pagerequest)の独自のコピーを取得します。 foundはローカルではないスコープで宣言されているため(おそらくとにかく)、実行中のすべてのインスタンスの間で共有されます(BusyWait)。結果として、同期メカニズムが存在しないため、現在のfoundの読み取りと書き込みはスレッドセーフではありません。

+0

この回答をありがとう。あなたは私が見ていた別のバグを解決したかもしれません。ちょうど私は記事を正しく理解しています。私のforeachループでは、canidateを保持する新しい変数を作成し、これをBusyWait関数に渡す必要がありますか? – user489041

+0

良いキャッチ、私は完全にそれを逃した。 (ホーマーはいいですが、上にあると考えられます)。 –

+0

@HenkHolterman:真...削除されました。 –

関連する問題