2012-03-08 125 views
3

基本上,我需要忙于等待,直到网页上出现一些html。我创建了以下代码忙等待对我来说:繁忙的等待线程

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,它会催生关闭8个线程,每个正在寻找claim all出现在网页上。 found是一个全局变量。一旦其中一个线程发现claim all,他们都应该保释。

我对这种方法有几个问题。首先,它是一个好方法。其次,每个线程都会获得自己的忙等待函数的“副本”。我的意思是,一个线程可以抢占另一个线程并更改该函数中的数据,或者它们每个都获得函数内声明的变量的副本。请注意,这两个函数都在同一个对象内。

+1

有效的技术问题,但看起来像试图在扑克或拍卖作弊。 – 2012-03-08 18:21:28

回答

2

其次,将每个线程获得忙等待功能的它自己的“副本”

每个线程将与它自己的堆栈空间执行的功能,这样就意味着任何变量,它是本地内你的函数将属于它正在运行的线程。如果你有一个全局变量,比如你的found变量在函数内被修改,你需要设置一个同步机制,这样就不会同时在多个线程中对它进行访问,因为这样会导致很难发现错误和很多恐怖,你永远不想想象经历!

2

所有线程都获得自己的局部变量副本(在这种情况下只有string page)。

您共享found变量应被声明为volatile

这是一种罕见的情况下,以Thread.Sleep()通话可能会做一些很好的。在呼叫同一站点之间插入一点呼吸器。

+0

我真的想过要这样做。但是,您能否详细说明添加Thread.Sleep()的好处。我的申请实际上是在与其他人竞争。首先检测“索赔全部”按钮是非常重要的。会添加一个Thread.Sleep()帮助还是伤害这种情况?谢谢 – user489041 2012-03-08 19:26:44

+0

一个短暂的Sleep()将减轻系统的其他部分,并使8个任务的处理更加平等。但为了在最后一秒有竞争力,不要睡觉()。 – 2012-03-08 19:43:32

2

每个线程都使用自己的变量副本运行。

但是我会修改我的appoarch。使用找到的变量不是线程安全的。一次有多个线程可能会发生更改。一个线程正在读取而另一个线程正在写入,这也是非常可能的。 [lock][1]可以避免这种情况。

解决此问题的更好方法是使用EventWaitHandle。这样,你不必担心锁定,你可以在睡眠或超时时间内建立,所以如果没有出现“索赔全部”,你的线程将不会比你想的更长。

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; 
    } 
} 

Here是一个出色的免费threading

5

在我回答你的问题之前,我必须指出你犯下了closing over the loop variable这个令人震惊的行为。

首先,它是一个很好的方法。

不,不是真的。任意创建线程通常不是一个好主意。最好使用线程池技术。这可以通过ThreadPool.QueueUserWorkItemTask类完成。

其次,将每个线程获得忙等待功能的自己的“副本”。 我的意思是,一个线程是否可以抢占另一个线程并更改 中的函数,或者它们是否都获取函数内部声明为 的变量的副本。

BusyWait每个正在运行的实例会得到自己的所有局部变量(即pagerequest)的副本。由于found在非本地范围内被声明(大概无论如何),因此它将在所有正在运行的BusyWait实例中共享。因此,您当前的读写found不是线程安全的,因为没有适当的同步机制。

+0

感谢您的回答。您可能已经解决了我所看到的另一个错误。只是让我正确理解这篇文章。在我的foreach循环中,我需要创建一个包含canidate的新变量,然后将其传递给BusyWait函数? – user489041 2012-03-08 19:43:59

+0

好,我完全错过了。 (荷马很好,但可能会考虑顶部)。 – 2012-03-08 19:44:11

+0

@HenkHolterman:确实...已删除。 – 2012-03-08 19:59:00