C# 中用delegate傳遞多個參數給多線程的疑問及探索


  在線程編程中,我們都知道一般給線程傳遞參數的大致有三種方式:

 

1.方式一:使用ParameterizedThreadStart委托

如果使用了ParameterizedThreadStart委托,線程的入口必須有一個object類型的參數,且返回類型為void.

View Code
using System;
 using System.Threading;
  
 namespace ThreadWithParameters
 {
     class Program
     {
         static void Main(string[] args)
         {
             string hello = "hello world";
  
             //這里也可簡寫成Thread thread = new Thread(ThreadMainWithParameters);
             //但是為了讓大家知道這里用的是ParameterizedThreadStart委托,就沒有簡寫了
             Thread thread = new Thread(new ParameterizedThreadStart(ThreadMainWithParameters));
             thread.Start(hello);
  
             Console.Read();
         }
  
         static void ThreadMainWithParameters(object obj)
         {
             string str = obj as string;
             if(!string.IsNullOrEmpty(str))
                 Console.WriteLine("Running in a thread,received: {0}", str);
         }
     }
 }

以上代碼只能傳遞一個參數,如果有時我們向線程傳遞給多的參數,那種方式使用將有局限性(如果用類作為對象傳遞參數,那么需要要另外建立一個類,也稍有點麻煩)
如果用這種方法我們密切要注意的就是ThreadMainWithParameters方法里的參數必須是object類型的,我們需要進行類型轉換。此方法不作推薦。

 2.方式二: 創建自定義類

定義一個類,在其中定義需要的字段,將線程的主方法定義為類的一個實例方法,請看實際的例子。

View Code
using System;
 using System.Threading;
  
 namespace ThreadWithParameters
 {
     public class MyThread
     {
         private string data;
  
         public MyThread(string data)
         {
             this.data = data;
         }
  
         public void ThreadMain()
         {
             Console.WriteLine("Running in a thread,data: {0}", data);
         }
     }
  
     class Program
     {
         static void Main(string[] args)
         {
             MyThread myThread = new MyThread("hello world");
  
             Thread thread = new Thread(myThread.ThreadMain);
             thread.Start();
  
             Console.Read();
         }
     }
 }

這種方法也稍有繁瑣,也不是我重點想要探討的,如果需要,自己也可以使用。
3. 方式三:采用lambda表達式

對於lambda表達式不熟悉的可以查看微軟MSDN上的說明文檔。此處假設你熟悉。因為在大多數使用委托的時候我們一般也可以用lambda表達式的。

View Code
using System;
 using System.Threading;
  
 namespace ThreadWithParameters
 {
     class Program
     {
         static void Main(string[] args)
         {
             string hello = "hello world";
  
             //如果寫成Thread thread = new Thread(ThreadMainWithParameters(hello));這種形式,編譯時就會報錯
             Thread thread = new Thread(() => ThreadMainWithParameters(hello));
             thread.Start();
  
             Console.Read();
         }
  
         static void ThreadMainWithParameters(string str)
         {
              Console.WriteLine("Running in a thread,received: {0}", str);
         }
     }
 }

此方法三可以作為推薦方法,代碼簡便,方便我們使用。上面方式三說到lambda表達式,既然lambda表達式可以使用,那么我們也可以使用delegate委托。下面主要探討的是使用這種方法。
4. 方式三:使用delegate委托

Multhd = new Thread[ThreadCount];
            thread_Separate_baseCount = C_num / ThreadCount;//每個線程的終端數
            listViewEx2.Items.Clear();
            for (int j = 0; j < ThreadCount; j++)
            {
                if (j == ThreadCount - 1)//最后一個線程
                {
                    Multhd[j] = new Thread(delegate() { Run2( j * thread_Separate_baseCount,  C_num - 1); });
                }
                else//其它線程
                {
                    Multhd[j] = new Thread(delegate() { Run2( j * thread_Separate_baseCount, (j + 1) * thread_Separate_baseCount - 1); });
                }
}

上面代碼Run(arg1,arg2.....,argn)是我們自定義的方法,在這個方法中我們可以設置任意多個參數,看也算是簡單的吧。

以上代碼完全可以運行,也不會出現bug什么之類的,但是實際運行情況卻令我驚訝不已,用for循環創建一個線程時,關閉重開線程不會有任何問題。因為只是一個線程,可能沒有什么事。但是至二個或者二個以上時,關閉再重開線程(我需要不斷關閉打開終端),程序不會報錯,調試器也沒有什么問題,電腦有時會毫無預兆的關機,在我們做事時毫無預兆的關機這可是一個致命的問題啊,沒有誰願意這樣的。以為是偶然,重復了多次結果都一樣,偶然也必然存在這種必然。

為什么一個線程時沒事,多個線程時運行時是不是上面的線程都指向了同一個delegate委托的地址,才導致這樣會毫無預兆的關機?這些等待我們去驗證,在此熱烈歡迎有經驗的朋友和我一塊探討。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM