C#中的多線程–持續更新系列

來源:互聯網
上載者:User

  今年第一次旅行結束,雖然是第二次進去藏區,依舊有高原反應,嚓....不過整個旅途感受到前所未有的放鬆.更有精力面對接下來的工作和學習.進入今天的主題---C#中的多線程

1、感受多線程

因為文章追求是簡單易懂,如果您和我一樣,是C#初學者,那麼在這一段中,請跟著例子,寫一次,每個例子都有分析,並且這裡的例子是會把多線程涉及的很多問題先引入出來,在後面的階段,再深入分析~

 C#是支援多線程滴(貌似是廢話.)~一個線程有它獨立的執行路徑,能夠與其他的線程“同時”運行,一個C#程式起始於一個單線程,這個線程是被CLR和作業系統自動建立滴。~囉嗦了這麼多了,還是用一段簡單的代碼加以說明

第一個多線程程式

    class Program    {        static void Main(string[] args)        {            Thread t = new Thread(WriteYes);            t.Start();            while (true)            {                Console.Write("No");            }        }        static void WriteYes()        {            while (true)            {                Console.Write("Yes");            }        }    }

程式運行

程式分析:在主線程中建立了一個新的線程"t",完成的任務是重複的輸出"yes",同時主線程重複的列印"No",在這裡並沒有控制線程的執行,所以看到的運行結果是隨機的

首先,先看一段書本上的:CLR分配每個線程到自己的記憶體堆棧上,來保證局部變數的分離運行

多線程調用同一個方法,方法中局部變數執行問題

        static void Main(string[] args)        {            new Thread(Go).Start();            Go();        }        static void Go()        {            for (int cycles = 0; cycles < 5; cycles++)            {                Console.Write("??");            }        }

程式分析:在此程式中,聲明了一個方法Go,在Go這個方法中聲明並使用了一個局部變數'cycles',在主程式中,又開啟了一個線程(匿名線程)調用方法Go,和在主線程直接調用Go~通過運行結果可以看出,一共輸出了10個"?"

 由此,可見變數'cycles'分別在自己的記憶體堆棧中建立,互不影響!那是不是所有的情況都是如此的呢?答案顯然是否定的

線程中引用共用的執行個體,共用資料問題,還是先看代碼,通過代碼來分析

多線程共用執行個體

        #region 多線程共用執行個體        bool done;        static void Main(string[] args)        {            Program pp = new Program();//建立了一個Program的執行個體            new Thread(pp.Go).Start();            pp.Go();        }        //這裡和上面的“線程間局部變數”中的Go方法不一定,這裡是一個執行個體的方法,        //也就是需要new Program一個執行個體才可以調用        void Go()        {            if (!done) { done = true; Console.WriteLine("done"); }         }        #endregion

程式分析:在主程式中,聲明了一個Program執行個體pp,在相同的Program執行個體中,兩個線程都調用了方法Go,此時共用了done欄位,所以程式運行只輸出一個"done",而不是兩個

靜態欄位在多線程中的影響

多線程中的靜態欄位

        #region 多線程中的靜態欄位        static bool done;        static void Main(string[] args)        {            new Thread(Go).Start();            Go();        }        static void Go()        {            if (!done) { done = true; Console.WriteLine("done"); }         }        #endregion

程式運行結果:

 看到這裡,也許你會想,靜態欄位和執行個體欄位在多線程中是否沒有任何影響,稍等,我們將上面的代碼進行簡單的修改,將Go方法修改如下

修改後的Go方法

        static void Go()        {            if (!done) { Console.WriteLine("done"); done = true; }        }

在多次執行這個程式,輸出done的次數在1和2次之間沒規律的切換~

程式分析:從啟動並執行結果上看,這個輸出的次數就不受我們程式的控制,問題就是在一個線程在執行if判斷的時候,恰好此時另一個線程正在執行輸出語句WriteLine語句.當這個線程執行完WriteLine語句,在將done設定為true之前,執行if判斷的線程發現done還是為false,所以也會執行WriteLine語句.導致了問題的產生----安全執行緒問題

安全執行緒問題

那麼如何解決上面遇到的問題呢?拋開程式來說,我們兩個人去做一件事,那麼為了避免重複,我們可以這樣,先獲得做事許可權的人,先設定一個標誌,告訴後面來的人,我現在正在執行任務,請不要進入現場。程式中也是這樣的原理,在C#中提供了lock語句來實現(鎖的機制)

安全執行緒

        #region 安全執行緒        static bool done;        static object locker = new object();        static void Main(string[] args)        {            new Thread(Go).Start();            Go();            Console.Read();        }        static void Go()        {            lock (locker)            {                if (!done) { Console.WriteLine("done"); done = true; }            }        }        #endregion

我們再試著多次運行程式,會發現只會輸出一個done,當兩個線程在爭奪一個鎖的時候(例子中的是locker),一個線程會處於等待或者說是阻止狀態知道那個鎖變成可用,確保在同一時刻只有一個線程進入了工作區,所以保證只輸出了一次done.
在完成上面幾個簡單的例子之後,我們應該思考,在何時使用多線程~

何時使用多線程

其實這個話題,我想是仁者見仁智者見智了,但核心的思想都是一致的,多線程程式一般被用來在後台處於耗時的任務,主線程保持運行,並且背景工作執行緒在後台默默無聞的工作,對於Winform程式來說,如果主線程(UI線程)執行一段耗時操作的代碼,鍵盤和滑鼠的操作會變得很遲鈍,時間稍微長點,就整個程式就失去了響應。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.