C# 之多線程(二)

来源:http://www.cnblogs.com/Liyuting/archive/2017/05/10/6807139.html
-Advertisement-
Play Games

一、確定多線程的結束時間,thread的IsAlive屬性 在多個線程運行的背景下,瞭解線程什麼時候結束,什麼時候停止是很有必要的。 案例:老和尚念經計時,2本經書,2個和尚念,一人一本,不能撕破,最短時間念完,問老和尚們念完經書最短需要多長時間。 分析:首先在開始念經的時候給計時,記為A,最後在記 ...


一、確定多線程的結束時間,thread的IsAlive屬性

在多個線程運行的背景下,瞭解線程什麼時候結束,什麼時候停止是很有必要的。

案例:老和尚念經計時,2本經書,2個和尚念,一人一本,不能撕破,最短時間念完,問老和尚們念完經書最短需要多長時間。

分析:首先在開始念經的時候給計時,記為A,最後在記下慢和尚念完經書時的時間,記為B。求B-A

代碼:IsAlive屬性:標識此線程已啟動並且尚未正常終止或中止,則為 true,再念,沒念完,努力中;否則為 false,念完啦,歇著。

//和尚1,和尚2
        public Thread td1, td2;

        public void StarThread()
        {
            //開啟一個線程執行Hello方法,即和尚1念菠蘿菠蘿蜜
            ThreadStart ts = new ThreadStart(Hello);
            td1 = new Thread(ts);
            td1.Start();
        }
        public void StarThread1()
        {
            //開啟一個線程執行Welcome方法,即和尚2念大金剛經
            ThreadStart ts = new ThreadStart(Welcome);
            td2 = new Thread(ts);
            td2.Start();
        }
        public string sayh="", sayw="";

        //菠蘿菠蘿蜜
        public void Hello()
        {
            //
            sayh = "Hellow everyone ! ";
        }

        //大金剛經
        public  void Welcome()
        {   
            //
            sayw = "Welcome to ShangHai ! ";
            //偷懶10秒
            Thread.Sleep(10000);
        }

        protected void btn_StarThread_Click(object sender, EventArgs e)
        {
            //記時開始,預備念        
            Response.Write("開始念的時間: "+DateTime.Now.ToString() + "</br>");
            //和尚1就位
            StarThread();
            //和尚2就位
            StarThread1();

            int i = 0;
            while (i == 0)
            {
                //判斷線程的IsAlive屬性
                //IsAlive標識此線程已啟動並且尚未正常終止或中止,則為 true;否則為 false。
                //如果兩個都為false說明,線程結束終止
                if (!td1.IsAlive && !td2.IsAlive)
                {
                    i++;
                    if (i == 1)
                    {
                        //念得內容,繞梁三尺。
                        Response.Write("我們年的內容: "+(sayh + " + " + sayw) + "</br>");
                        Response.Write("念完時的時間: "+DateTime.Now.ToString());
                        Response.End();
                    }
                }
            }
        }

二、線程優先順序,thread的ThreadPriority屬性

 線程優先順序區別於線程占有cpu時間的多少,當然優先順序越高同等條件下占有的cpu時間越多。級別高的執行效率要高於級別低的。

優先順序有5個級別:Lowest<BelowNormal<Normal<AboveNormal<Highest;預設為Normal。

案例:老和尚娶媳婦。佛祖說:你們3個和尚,清修刻苦,現特許你們娶媳婦啦,不過娶媳婦的只能是你們三個中間的一人。條件是我手中的經書誰能先念完,誰可以娶。

分析:和尚平時都很刻苦,各有特點,平時和尚1在lowest環境下念經,和尚2在normal環境下念經,和尚3在Highest環境下念經。

protected void btn_StarThread_Click(object sender, EventArgs e)
        {
            Write();
        }

        //i為和尚1念的頁數
        //j為和尚2念的頁數
        //k為和尚3念的頁數
        //c為經書總頁數
        int i=0,j=0,k=0,c=10000000;

        //和尚1念經
        public void Jsi()
        {
            while (i <= c)
            {
                i+=1;
            }
        }
        //和尚2念經
        public void Jsj()
        {
            while (j <= c)
            {
                j+=1;
            }
        }
        //和尚3念經
        public void Jsk()
        {
            while (k <= c)
            {
                k+=1;
            }
        }
        public void Write()
        {
            //開啟線程計算i
            ThreadStart sti = new ThreadStart(Jsi);
            Thread tdi = new Thread(sti);
            //設置線程優先順序為Lowest。和尚1在Lowest環境下念經
            tdi.Priority = ThreadPriority.Lowest;

            //開啟線程計算j
            ThreadStart stj = new ThreadStart(Jsj);
            Thread tdj = new Thread(stj);
            //設置線程優先順序為Normal。和尚2在Normal環境下念經
            tdj.Priority = ThreadPriority.Normal;            

            //開啟線程計算k
            ThreadStart stk = new ThreadStart(Jsk);
            Thread tdk = new Thread(stk);
            //設置線程優先順序為Highest。和尚3在Highest環境下念經
            tdk.Priority = ThreadPriority.Highest;         
            
            //開始
            tdj.Start();
            tdk.Start();
            tdi.Start();
            int s = 0;
            while (s==0)
            {                
                if (k > c)
                {
                    s++;
                    Response.Write("比賽結束,結果如下:</br></br>");
                    Response.Write("和尚1在Lowest環境下念經:" + i + "頁</br>和尚2在Normal環境下念經:" + j + "頁</br>和尚3在Highest環境下念經:" + k + "頁</br></br>");
                    Response.Write("佛祖又說:你念或者不念,蒼老師,就在那裡!");
                    Response.End();
                }
            }
        }       註意:Lowest優先順序可能會出現執行快於normal優先順序的情況。

三、線程通信之Monitor類

 如果,你的線程A中運行鎖內方法時候,需要去訪問一個暫不可用資源B,可能在B上需耗費很長的等待時間,那麼這時候你的線程A,將占用鎖內資源,阻塞其它線程訪問鎖定內容,造成性能損失。你該怎麼解決這樣子的問題呢?這樣,讓A暫時放棄鎖,停留在鎖中的,允許其它線程訪問鎖,而等B資源可用時,通知A讓他繼續鎖內的操作。是不是解決啦問題,這樣就用到啦這段中的Monitor類,提供的幾個方法:Wait(),Pulse(),PulseAll(),這幾個方法只能在當前鎖定中使用。

Wait():暫時中斷運行鎖定中線程操作,釋放鎖,時刻等待著通知複活。

Pulse():通知等待該鎖線程隊列中的第一個線程,此鎖可用。

PulseAll():通知所有鎖,此鎖可用。

案例:嵩山少林和尚開會。主持人和尚主持會議會不停的上舞臺講話,方丈會出來宣佈大會開始,弟子們開始討論峨眉山怎麼走。

分析:主持人一個線程,方丈一個線程,弟子們一個線程,主持人貫徹全場。

public class MutexSample
    {
        static void Main()
        {
            comm com = new comm();
            com.dhThreads();
            Console.ReadKey();
        }
    }
    public class comm
    {
        //狀態值:0時主持人和尚說,1時方丈說,2時弟子們說,3結束。
        int sayFla;
        //主持人上臺
        int i = 0;
        public void zcrSay()
        {
            lock (this)
            {
                string sayStr;
                if (i == 0)
                {
                    //讓方丈說話
                    sayFla = 1;
                    sayStr = Thread.CurrentThread.Name+"今晚,陽光明媚,多雲轉晴,方丈大師,程祥雲而來,傳揚峨眉一隅,情況如何,還請方丈閃亮登場。";
                    Console.WriteLine(sayStr);
                    i++;
                    //此時sayFla=1通知等待的方丈線程運行
                    Monitor.Pulse(this);  
                    //暫時鎖定主持人,暫停到這裡,釋放this讓其它線程訪問
                    Monitor.Wait(this);
                    
                }
                //被通知後,從上一個鎖定開始運行到這裡
                if (i == 1)
                {
                    //讓弟子說話
                    sayFla = 2;
                    sayStr = Thread.CurrentThread.Name + "看方丈那幸福的表情,徜徉肆恣,願走的跟他去吧。下麵請弟子們各抒己見";
                    Console.WriteLine(sayStr);
                    i++;
                    //此時sayFla=12通知等待的弟子線程運行
                    Monitor.Pulse(this);  
                     //暫時鎖定主持人,暫停到這裡,釋放this讓其它線程訪問
                    Monitor.Wait(this);                    
                }
                //被通知後,從上一個鎖定開始運行到這裡
                if (i == 2)
                {
                    sayFla = 3;
                    sayStr = Thread.CurrentThread.Name + "大會結束!方丈幸福!!蒼老師你在哪裡?!!放開那女孩 ...";
                    Console.WriteLine(sayStr);
                    i++;
                    Monitor.Wait(this); 
                }
            }
        }
        //方丈上臺
        public void fzSay()
        {
            lock (this)
            {
                while (true)
                {
                    if (sayFla != 1)
                    {
                        Monitor.Wait(this);
                    }
                    if (sayFla == 1)
                    {
                        Console.WriteLine(Thread.CurrentThread.Name + "藍藍的天空,綠綠的湖水,我看見,咿呀呀呀,看見一老尼,咿呀呀,在水一方。願意來的一起來,不願來的蒼老師給你們放寺里。。咿呀呀,我走啦。。。");
                        //交給主持人
                        sayFla = 0;
                        //通知主持人線程,this可用
                        Monitor.Pulse(this);
                    }
                }                
            }
        }
        //弟子上臺
        public void dzSay()
        {
            lock (this)
            {
                while (true)
                {
                    if (sayFla != 2)
                    {
                        Monitor.Wait(this);  
                    }
                    if (sayFla == 2)
                    {
                        Console.WriteLine(Thread.CurrentThread.Name + "果真如此的話,還是方丈大師自己去吧!! 祝福啊  .... ");
                        //交給主持人
                        sayFla = 0;
                        Monitor.Pulse(this);
                    }
                }
                
            }
        } 
        public void dhThreads()
        {            
                Thread zcrTd = new Thread(new ThreadStart(zcrSay));
                Thread fzTd = new Thread(new ThreadStart(fzSay));
                Thread dzTd = new Thread(new ThreadStart(dzSay));
                zcrTd.Name = "主持人:";
                fzTd.Name = "方丈:";
                dzTd.Name = "弟子:";                
                zcrTd.Start();
                fzTd.Start();
                dzTd.Start();
        }
    }

四、線程排隊之Join

多線程,共用一個資源,先後操作資源。Join()方法,暫停當前線程,直到指定線程運行完畢,才喚醒當前線程。如果沒有Join,多線程隨機讀取公用資源,沒有先後次序。

案例:兩個和尚念一本經書,老和尚年前半本書,小和尚念後半本書,小和尚調皮,非要先念,就給老和尚用迷魂藥啦。。

分析:一本書6頁,小和尚4-6,老和尚1-3,兩個和尚,兩個線程。

public class 連接線程Join
    {
        //小和尚
        public static Thread litThread;
        //老和尚
        public static Thread oldThread;

        //老和尚念經
        static void oldRead()
        {
            //老和尚被小和尚下藥
            litThread.Join();  //暫停oldThread線程,開始litThread,直到litThread線程結束,oldThread才繼續運行,如果不適用Join將小和尚一句,老和尚一句,隨即沒有規則的。
            for (int i = 1; i <= 3; i++)
            {
                Console.WriteLine(i);
            }
        }
        //小和尚念經
        static void litRead()
        { 
            for (int i = 4; i <= 6; i++)
            {
                Console.WriteLine(i);
            }
        }
        static void Main(string[] args)
        {
            oldThread = new Thread(new ThreadStart(oldRead));
            litThread = new Thread(new ThreadStart(litRead));

            oldThread.Start();
            // FristThread.Join();   //暫停oldThread線程,開始litThread,直到litThread線程結束,oldThread才繼續運行
            litThread.Start();
            Console.ReadKey();
        }
    }

五、多線程互斥鎖Mutex

互斥鎖是一個同步的互斥對象,適用於,一個共用資源,同時只能有一個線程能夠使用。

共用資源加互斥鎖,需要兩部走:1.WaitOne(),他將處於等待狀態知道可以獲取資源上的互斥鎖,獲取到後,阻塞主線程運行,直到釋放互斥鎖結束。2.ReleaseMutex(),釋放互斥鎖,是其它線程可以獲取該互斥鎖。

案例:和尚寫日記。最近寺廟香火不旺,為啦節約用水,方丈發話兩個和尚用一個本子寫日記。

分析:好比多個線程寫日誌,同時只能有一個線程寫入日誌文件。

public class 多線程互斥鎖Mutex
    {
        static void Main(string[] args)
        {
            IncThread ict = new IncThread("大和尚", 3);
            DecThread dct = new DecThread("小和尚", 3);
            Console.ReadKey();
        }
    }
    class SharedRes
    {
        public static int count = 0;
        //初始化互斥鎖,沒被獲取
        public static Mutex mtx = new Mutex();
        ////初始化互斥鎖,被主調線程獲取
        //public static Mutex mtx = new Mutex(true);
    }

    class IncThread
    {
        int num;
        public Thread thrd;
        public IncThread(string name ,int n)
        {
            thrd = new Thread(new ThreadStart(this.run));
            thrd.Name = name;
            num = n;
            thrd.Start();
        }
        //寫日記,過程
        void run()
        {
            Console.WriteLine(thrd.Name + " , 等待互斥鎖 。");
            SharedRes.mtx.WaitOne();           
            Console.WriteLine(thrd.Name + " ,獲得互斥鎖 。");
            do
            {
                Thread.Sleep(500);
                SharedRes.count++;
                Console.WriteLine("今天我 " + thrd.Name + " 比較強,這樣寫吧 :" + SharedRes.count);
                num--;
            }while(num>0);
           Console.WriteLine(thrd.Name + " , 釋放互斥鎖 。");
           SharedRes.mtx.ReleaseMutex();
        }
    }
    class DecThread
    {
        int num;
        public Thread thrd;

        public DecThread(string name, int n)
        {
            thrd = new Thread(new ThreadStart(this.run));
            thrd.Name = name;
            num = n;
            thrd.Start();
        }
        //寫日記,過程
        void run()
        {           
            Console.WriteLine(thrd.Name + ", 等待互斥鎖 。");
            SharedRes.mtx.WaitOne();
            Console.WriteLine(thrd.Name + " ,獲得互斥鎖 。");
            do
            {
                Thread.Sleep(500);
                SharedRes.count--;
                Console.WriteLine("今天我 " + thrd.Name + " 比較衰,這樣寫吧 :" + SharedRes.count);
                num--;
            } while (num > 0);
            Console.WriteLine(thrd.Name + " , 釋放互斥鎖 。");
            SharedRes.mtx.ReleaseMutex();
        }
    }

六、信號量semaphore

類似於互斥鎖,只不過他可以指定多個線程來訪問,共用資源。在初始化信號量的同時,指定多少個線程可以訪問,假如允許2個線程訪問,而卻有3個線程等待訪問,那麼他將只允許2個訪問,一旦已訪問的2個線程中有一個訪問完成釋放信號量,那麼沒有訪問的線程立馬可以進入訪問。

案例:和尚抓雞,3個和尚抓雞,只有兩隻雞,那麼雞圈管理員只允許2個和尚先進,抓到說三句話放下,出來,讓第三個和尚進去抓。

分析:三個線程,初始信號量允許2個線程訪問。

public class 信號量semaphore
    {
       static void Main(string[] args)
       {
           MyThread td1 = new MyThread("降龍");
           MyThread td2 = new MyThread("伏虎");
           MyThread td3 = new MyThread("如來");           
           td1.td.Start();
           td2.td.Start();
           td3.td.Start();
           Console.ReadKey();
       }    
    }

  public class MyThread
   {
       //初始化,新號量,允許2個線程訪問,最大2也是2個。
       public static Semaphore sem = new Semaphore(2,2);
       public Thread td;
       public MyThread(string name)
       {
           td = new Thread(new ThreadStart(this.Run));
           td.Name = name;
       }
       //過程很美好
       public void Run()
       {
           Console.WriteLine(td.Name+",等待一個信號量。");
           sem.WaitOne();
           Console.WriteLine(td.Name+",已經獲得新號量。");
           Thread.Sleep(500);
           //很有深意的三句話
           char[] cr = { 'a','o','e'};
           foreach (char v in cr)
           {
               Console.WriteLine(td.Name+",輸出v: "+v);
               Thread.Sleep(300);
           }
           Console.WriteLine(td.Name+",釋放新號量。");
           sem.Release();
       }
   }

 

 

結束,笑納,海涵。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、先附上一份值類型和引用類型各自的成員 2、值類型和引用類型的區別 值類型直接存儲其值,引用類型存儲其值的引用 值類型變數都存儲在堆棧中,引用類型在托管堆中分配存儲單元 值類型變數不能為null,必須有確定的值,引用類型被賦值前的值都是null 值類型是從System.ValueType類繼承而來 ...
  • 如果對象可以改變其狀態,就很難在多個同時運行的任務中使用。這些集合必須同步。如果對象不能改變器狀態,就很容易在多個線程中使用。 Microsoft提供了一個新的集合庫:Microsoft Immutable Collection。顧名思義,它包含不變的集合類————創建後不能改變的集合類。該類在Sy ...
  • 0. 寫在前面 1. 建立運行環境 2. 添加實體和映射資料庫 1. 準備工作 2. Data Annotations 3. Fluent Api 3. 包含和排除實體類型 1. Data Annotations [NotMapped] 排除實體和屬性 2. Fluent API [Ignore] ...
  • 如果需要集合中的元素何時刪除或添加的信息,可以使用ObservableCollection<T>類。這個類是為WPF定義的,這樣UI就可以得知集合的變化。這個類在程式集WindowsBase中定義,需要引用這個程式集。 ObservableCollection<T>類派生自Collection<T> ...
  • 包含不重覆元素的集合稱為“集(set)”。.NET Framework包含兩個集HashSet<T>和SortedSet<T>,它們都實現ISet<T>介面。HashSet<T>集包含不重覆元素的無序列表,SortedSet<T>集包含不重覆元素的有序列表。 ISet<T>介面提供的方法可以創建合集 ...
  • ListView是個較為複雜的控制項 ListView是個較為複雜的控制項 ListView是個較為複雜的控制項 1.定義 把它拽進來,系統會自動在Designer.cs里添加一個 this.listView1 = new System.Windows.Forms.ListView(); 2.初始化,確定 ...
  • 字典表示一種複雜的數據結構,這種數據結構允許按照某個鍵來訪問元素。字典也稱為映射或散列表。 字典的主要特性是能根據鍵快速查找值。也可以自由添加和刪除元素,這有點像List<T>(http://www.cnblogs.com/afei-24/p/6824791.html),但沒有在記憶體中移動後續元素的 ...
  • 1 /// 2 /// 短鏈生成 3 /// 4 public class ShortUrlBuilder 5 { 6 private static readonly string[] Chars = 7 { "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h"... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...