2012-09-06 54 views
0

我正在尝试在我的应用程序中使用多线程。方法test5尝试从Internet获取一些内容,而main线程在继续其他工作之前等待所有线程完成。当子线程完成时主线程无法继续

但我的main线程调用test5后不会回来,我的控制台行Done Inside!!thread all got back!!永远不会到达。

我该如何解决这个问题?

class Program 
{ 
    static void Main(string[] args) 
    { 
     string[] url = 
     { 
      "http://...", "http://...", "http://...", "http://...", "http://..." 
     }; 

     test5(url); 
     Console.WriteLine("thread all got back!!"); 

     // Do some other work after all threads come back 
     Console.ReadLine(); 
    } 

    private static void test5(string[] _url) 
    { 
     int numThreads = _url.Length; 
     ManualResetEvent resetEvent = new ManualResetEvent(false); 
     int toProcess = numThreads; 

     for (int i = 0; i < numThreads - 1; i++) 
     { 
      new Thread(delegate() { 
       testWebWorking(_url[i]); 
       if (Interlocked.Decrement(ref toProcess) == 0) 
        resetEvent.Set(); 
      }).Start(); 
     } 
     resetEvent.WaitOne(); 
     Console.WriteLine("Done inside!!"); 
    } 

    private static void test6(string[] _url) 
    { 
     int numThreads = _url.Length; 
     var countdownEvent = new CountdownEvent(numThreads); 

     for (int i = 0; i < numThreads - 1; i++) 
     { 
      new Thread(delegate() { 
       testWebWorking(_url[i]); 
       countdownEvent.Signal(); 
      }).Start(); 
     } 
     countdownEvent.Wait(); 
     Console.WriteLine("Done inside!!"); 
    } 

    private static void testWebWorking(object url) 
    { 
     Console.WriteLine("start {0}", Thread.CurrentThread.ManagedThreadId); 
     string uri = (string)url; 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 
     request.KeepAlive = true; 
     request.Timeout = 5000; 
     request.ReadWriteTimeout = 5000; 
     request.Proxy = null; 

     try 
     { 
      using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
      { 
       //Console.WriteLine(response.ContentType + "; uri = " + uri); 
       Stream receiveStream = response.GetResponseStream(); 
       Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 
       // Pipes the stream to a higher level stream reader with the required encoding format. 
       StreamReader readStream = new StreamReader(receiveStream, encode); 
       //Console.WriteLine("\r\nResponse stream received."); 
       Char[] read = new Char[256]; 
       // Reads 256 characters at a time.  
       int count = readStream.Read(read, 0, 256); 
       //Console.WriteLine("HTML...\r\n"); 
       String str = ""; 
       while (count > 0) 
       { 
        // Dumps the 256 characters on a string and displays the string to the console. 
        str = new String(read, 0, count); 
        //Console.Write(str); 
        count = readStream.Read(read, 0, 256); 
       } 
       //Console.WriteLine(str); 
       // Releases the resources of the response. 
       response.Close(); 
       // Releases the resources of the Stream. 
       readStream.Close(); 

       Console.WriteLine("end {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
     catch (WebException ex) 
     { 
      //Console.WriteLine(ex.GetBaseException().ToString()); 
      //Console.WriteLine(url); 
      Console.WriteLine("time out !!"); 
     } 
     finally 
     { 
      request.Abort(); 
      request = null; 
      GC.Collect(); 
     } 
    } 
} 

回答

2

看看这个:

for (int i = 0; i < numThreads - 1; i++) 

你只是开始numThreads - 1线程。你的计数器从numThreads和倒计数,所以它会永远只能达到1,不是0

顺便说一句,这也打破::

for (int i = 0; i < numThreads - 1; i++) 
{ 
    new Thread(delegate() 
    { 
     testWebWorking(_url[i]); 
     ... 
    } 
    ... 
} 

在这里,你会捕捉变量i在委托内,因此在执行它时将具有任何值i。您可能会不止一次地测试相同的URL,并跳过其他网址。相反,你应该的i值复制到一个变量循环,让您每次拍摄不同的变量:

// Fixed the loop boundary as well 
for (int i = 0; i < numThreads; i++) 
{ 
    int copy = i; 
    new Thread(() => // Use a lambda expression for brevity 
    { 
     // Fix naming convention for method name, too... 
     TestWebWorking(_url[copy]); 
     if (Interlocked.Decrement(ref toProcess) == 0)) 
     { 
      resetEvent.Set(); 
     } 
    }).Start() 
} 

的你的方法都具有相同的一系列问题。

个人而言,我不会用这里for环反正 - 我会使用一个foreach循环:

private static void TestWithResetEvent(string[] urls) 
{ 
    ManualResetEvent resetEvent = new ManualResetEvent(false); 
    int counter = urls.Length; 

    foreach (string url in urls) 
    { 
     string copy = url; 
     Thread t = new Thread(() => 
     { 
      TestWebWorking(copy); 
      if (Interlocked.Decrement(ref toProcess) == 0)) 
      { 
       resetEvent.Set(); 
      } 
     }); 
     t.Start(); 
    } 
    resetEvent.WaitOne(); 
    Console.WriteLine("Done inside!!"); 
} 

或者,这将是简单的使用Parallel.ForEach,这是专为正是这样的事情。

+0

谢谢,它运作良好。这只是在我的问题的演示,所以我只是使用** for循环**显示它。在实际的代码中,我使用多个** while while循环**,因为实际情况有点复杂。 –

+0

在我的真实代码中,** numThreads **是未知的,我有多个while循环内相互。 ** numThreads **直到所有循环完成才知道......我该如何解决它?在我所有复杂的while循环完成之后,我是否应该释放线程?或者如上所示,我可以在我的循环内激发线程? –

相关问题