国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
多線程程(二):Thread

System.Threading命名空間提供了許多類型用來構(gòu)建多線程應(yīng)用程序。比如訪問線程池、Timer類、以及大量的用來同步訪問共享資源的類型。其中最基礎(chǔ)的類型是Thread。使用該類型中定義的方法能夠在當(dāng)前應(yīng)用程序域中創(chuàng)建、掛起、停止和銷毀線程。

(通過Thread可以獲得當(dāng)前線程的統(tǒng)計信息)

 

 

以編程方式創(chuàng)建次線程

可以通過ThreadStrat委托和ParameterizedThreadStart委托執(zhí)行在次線程中執(zhí)行的方法。前者執(zhí)行一個沒有參數(shù)、無返回值的方法,局限是無法給過程傳遞參數(shù),所以這一委托通常被設(shè)計用來正在后臺運行、而沒有更多的交互作用。后者則允許包含一個System.Object類型的參數(shù)。

ThreadStrat使用

 


public class Printer
{
    
public void PrintNumbers()
    {
     }
}

Printer p 
= new Printer();
Thread backgroundThread 
=new Thread(new ThreadStart(p.PrintNumbers));
backgroundThread.Name 
= "Secondary";
backgroundThread.Start();

 

 PParameterizedThreadStart使用

//傳遞給次線程
AddParams ap = new AddParams(1010);
Thread t 
= new Thread(new ParameterizedThreadStart(Add));
t.Start(ap);

 

 

 

 

臺線程和后臺線程

 

前臺線程:能阻止應(yīng)用程序的終結(jié)。一直到所有前臺線程終止后,CLR才能關(guān)閉應(yīng)用程序(就是卸載應(yīng)用程序域);

后臺線程(有時候也叫守護線程,daemon thread):被CLR認(rèn)為是程序中執(zhí)行中可以做出犧牲的途徑,在任何時候,當(dāng)應(yīng)用程序結(jié)束時(主程序結(jié)束),所有后臺線程也會被自動終止(不管是否在執(zhí)行)。

      

 所有通過Thread.Start()方法創(chuàng)建的線程都自動式前臺線程。意味著,知道所有線程本身單元的工作都執(zhí)行完成了,應(yīng)用程序才會被下載。另外,只要把IsBackground 屬性改成true,那么該線程就變成后臺線程

看下面的代碼:

 


public class Printer
{
    
public void PrintNumbers()
    {
      Console.WriteLine(
"-> {0} is executing PrintNumbers()",
          Thread.CurrentThread.Name);
      Console.Write(
"Your numbers: ");
      
for (int i = 0; i < 10; i++)
      {
        Console.Write(
"{0}, ", i);
        Thread.Sleep(
2000);
      }
      Console.WriteLine();
    }
}


class Program
{
    
static void Main(string[] args)
    {
      Console.WriteLine(
"***** Background Threads *****\n");
      Printer p 
= new Printer();
      Thread bgroundThread 
=
          
new Thread(new ThreadStart(p.PrintNumbers));
      
// 后臺線程
      bgroundThread.IsBackground = true;
      bgroundThread.Start();
    }
}

 

本來,成灰應(yīng)該打印出1---9,然后才會退出。在Main()方法執(zhí)行完畢,應(yīng)用程序就會自動結(jié)束,次線程雖然還在運行,但是,設(shè)置了打印的線程為后臺線程,所以它也被結(jié)束了。看不到完整的輸出。把該語句去掉以后,可以看到完整的輸出。

 

并發(fā)問題

看下面的代碼:

 

Code

在該程序域中的主線程產(chǎn)生了10個工作線程,每個工作線程同時執(zhí)行同一個Printer實例的PrintNumbers()方法。由于沒有預(yù)防鎖定共享資源。所以在PrintNumders()輸出到控制臺之前,調(diào)用PrintNumders()方法的線程可能會被掛起。當(dāng)每個線程都調(diào)用Printer來輸出數(shù)字的時候,線程調(diào)度器可能正在切換線程,這導(dǎo)致了不同的輸出結(jié)果。

 

(一種可能的結(jié)果)

 

使用lock關(guān)鍵字

對于上面的問題,需要一種方式來通過編程控制對共享資源的同步訪問。首選的是lock關(guān)鍵字。這個關(guān)鍵字允許定義一段線程同步的代碼語句。采用這種方式,后進入的線程不會中斷當(dāng)前線程,而是停止自身的下一步執(zhí)行。Lock關(guān)鍵字需要一個標(biāo)記,即一個引用對象,線程在進入鎖定訪問的時候必須獲得這個標(biāo)記。當(dāng)試圖鎖定的是一個實例級對象的私有方法時,使用方法本身所在對象的引用就可以了。將上面的代碼,修改為:

 

 


// 鎖標(biāo)記(如果要鎖定靜態(tài)方法,只需要一個私有靜態(tài)對象成員作為鎖標(biāo)記)
private object threadLock = new object();

public void PrintNumbers()
{
    
lock (threadLock)
    
{
     
//顯示線程信息
      Console.WriteLine("-> {0} is executing PrintNumbers()",
       Thread.CurrentThread.Name);
     
// 輸出數(shù)字
      Console.Write("Your numbers: ");
     
for (int i = 0; i < 10; i++)
     
{
       
//線程休眠秒數(shù)
         Random r = new Random();
        Thread.Sleep(
100 * r.Next(5));
        Console.Write(
"{0}, ", i);
      }

      Console.WriteLine();
   }

}

 

看到,結(jié)果如下:

 

 

 

使用System.Threading.Monitor進行同步

Lock關(guān)鍵字實際上是和System.Threading.Monitor類一同使用時的速記符號。經(jīng)過編譯器的處理,鎖定區(qū)域?qū)嶋H上被轉(zhuǎn)換為如下內(nèi)容:

 


  Monitor.Enter(threadLock );
  
try
  {
      
//顯示線程信息
       Console.WriteLine("-> {0} is executing PrintNumbers()",
         Thread.CurrentThread.Name);
      
// 輸出數(shù)字
      Console.Write("Your numbers: ");
     
for (int i = 0; i < 10; i++)
     {
        
//線程休眠秒數(shù)
         Random r = new Random();
        Thread.Sleep(
100 * r.Next(5));
        Console.Write(
"{0}, ", i);
     }
     Console.WriteLine();

   }
  
finally
  {
    Monitor.Exit(threadLock);
  }

    

 

 

相比較于lock,使用System.Threading.Monitor可以有更好的控制能力。使用該類型,可以(使用Wait()方法)只是活動的線程等待一段時間,在當(dāng)前線程完成操作時,使用(Pulse()或PulseAll())通知等待中的線程。

 

使用System.Threading.Interlocked進行原子操作

在底層的CIL代碼,賦值和簡單的數(shù)字運算都不是原子操作。System.Threading.Interlocked類允許我們來原子型操作單個數(shù)據(jù),使用它比Monitor更簡單。

 

 

Increment 和 Decrement 方法遞增或遞減變量并將結(jié)果值存儲在單個操作中。在大多數(shù)計算機上,增加變量操作不是一個原子操作,需要執(zhí)行下列步驟: 

1.將實例變量中的值加載到寄存器中。

2.增加或減少該值。

3.在實例變量中存儲該值。

 

如果不使用 Increment 和 Decrement,線程會在執(zhí)行完前兩個步驟后被搶先。然后由另一個線程執(zhí)行所有三個步驟。當(dāng)?shù)谝粋€線程重新開始執(zhí)行時,它覆蓋實例變量中的值,造成第二個線程執(zhí)行增減操作的結(jié)果丟失。

 

public void AddOne()
{
    
int newVal = Interlocked.Increment(ref intVal);
}

Exchange 方法自動交換指定變量的值。CompareExchange 方法組合了兩個操作:比較兩個值以及根據(jù)比較的結(jié)果將第三個值存儲在其中一個變量中。比較和交換操作按原子操作執(zhí)行。例如,想將83賦給一個成員變量:

 

public void SafeAssignment()
{
   
int newVal = Interlocked.Exchange(ref intVal,83);
}

 

使用[Synchronization]進行同步

最后一個同步原語是[Synchronization]特性。它位于System.Runtime.Remoting.Contexts命名空間下。這個類級別的特性有效地使對象的所有實例的成員都保持線程安全。當(dāng)CLR分配帶[Synchronization]對象時,它會把這個對象放在同步上下文中。(它的主要問題是,即使一個方法沒有使用線程敏感的數(shù)據(jù),CLR仍然會鎖定對該費那個發(fā)的調(diào)用,這會降低性能)。

 

使用Timer Callback

許多程序需要定期調(diào)用具體費那個發(fā)。比如,可能有一個應(yīng)用程序需要在狀態(tài)欄上通過一個輔助函數(shù)顯示當(dāng)前時間,或,可能希望應(yīng)用程序調(diào)用一個輔助函數(shù),讓它執(zhí)行非緊迫的后臺任務(wù),比如,監(jiān)察是否擁有新郵件。像這些情況,可以使用System.Threading.TimerTimerCallback委托。

 

CLR線程池

為了提高效率,使用BeginInvoke()的時候,CLR并不會創(chuàng)建新的線程,委托的BeginInvoke()方法創(chuàng)建了維護的工作線程池??梢允褂?/font>ThreadingThreadPool類型與之交互。

如果想要使用池中的工作線程排隊執(zhí)行一個方法,可以使用ThreadPool.QueueUserWorkItem()方法。這個被重載的方法可以讓你傳遞一個可選的Object類型的自定義狀態(tài)數(shù)據(jù)給WaitCallback委托實例:

 


class ThreadPoolApp
{
  
public static void executeThreadPool()
  {
      Console.WriteLine(
"Main thread started. ThreadID = {0}",
           Thread.CurrentThread.ManagedThreadId);
      Printer p 
= new Printer();

      WaitCallback workItem 
= new WaitCallback(PrintTheNumbers);

      
// 調(diào)用這個方法10次
       for (int i = 0; i < 10; i++)
      {
         ThreadPool.QueueUserWorkItem(workItem, p);
      }
      Console.WriteLine(
"所有任務(wù)都已經(jīng)入隊,執(zhí)行");
  }

   
static void PrintTheNumbers(object state)
   {
       Printer task 
= (Printer)state;
       task.PrintNumbers();
    }
}

 

 

我們可以看到,比起顯示地創(chuàng)建線程對象,使用這個被CLR鎖維護的線程池的好是:

1.線程池減少了線程創(chuàng)建、開始。亭子的次數(shù),提高了效率。

2.使用線程池,能夠使我們的注意力費那個在業(yè)務(wù)邏輯上,而不是多線程架構(gòu)上

但是,有時候,還是需要手動管理。比如:

1.如果需要設(shè)置線程優(yōu)先級別,或者線程池中的線程總是后臺線程,且它的優(yōu)先級是默認(rèn)的。

2.如果需要有一個帶有固定標(biāo)識的線程便于退出、掛起或通過名字發(fā)現(xiàn)它。

 

 

        

BackgroundWorker組件的作用

它位于System.ComponentModel命名空間下,構(gòu)建一個Windows Forms桌面應(yīng)用且需要執(zhí)行在應(yīng)用程序主UI線程之外的線程中長期的任務(wù)(調(diào)用遠程服務(wù)、進行數(shù)據(jù)庫事務(wù)、下載大文件等等)時,BackgroundWorker就能發(fā)揮它的所用。(可以直接使用Threading下的類型,但是BackgroundWorker更加方便)。

要使用BackgroundWorker,我們只需要告訴它希望在后臺執(zhí)行那個方法并且調(diào)用RunWorkerAsync()即可。調(diào)用線程(通常是主線程)繼續(xù)正常運行,而工作方法會一步執(zhí)行。結(jié)束以后,BackgroundWorker類型會通過觸發(fā)RunWorkerCompleted事件來通知調(diào)用線程。

 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服