亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

c#多線程編程基礎

2020-01-24 02:48:46
字體:
來源:轉載
供稿:網友

無論您是為具有單個處理器的計算機還是為具有多個處理器的計算機進行開發,您都希望應用程序為用戶提供最好的響應性能,即使應用程序當前正在完成其他工作。要使應用程序能夠快速響應用戶操作,同時在用戶事件之間或者甚至在用戶事件期間利用處理器,最強大的方式之一是使用多線程技術。

多線程:線程是程序中一個單一的順序控制流程.在單個程序中同時運行多個線程完成不同的工作,稱為多線程。如果某個線程進行一次長延遲操作, 處理器就切換到另一個線程執行。這樣,多個線程的并行(并發)執行隱藏了長延遲,提高了處理器資源利用率,從而提高了整體性能。多線程是為了同步完成多項任務,不是為了提高運行效率,而是為了提高資源使用效率來提高系統的效率

一、進程與線程

進程,是操作系統進行資源調度和分配的基本單位。是由進程控制塊、程序段、數據段三部分組成。一個進程可以包含若干線程(Thread),線程可以幫助應用程序同時做幾件事(比 如一個線程向磁盤寫入文件,另一個則接收用戶的按鍵操作并及時做出反應,互相不干擾),在程序被運行后中,系統首先要做的就是為該程序進程建立一個默認線程,然后程序可 以根據需要自行添加或刪除相關的線程。它是可并發執行的程序。在一個數據集合上的運行過程,是系統進行資源分配和調度的一個獨立單位,也是稱活動、路徑或任務,它有兩方面性質:活動性、并發性。進程可以劃分為運行、阻塞、就緒三種狀態,并隨一定條件而相互轉化:就緒--運行,運行--阻塞,阻塞--就緒。

線程(thread),線程是CPU調度和執行的最小單位。有時被稱為輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以并發執行。由于線程之間的相互制約,致使線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。

主線程,進程創建時,默認創建一個線程,這個線程就是主線程。主線程是產生其他子線程的線程,同時,主線程必須是最后一個結束執行的線程,它完成各種關閉其他子線程的操作。盡管主線程是程序開始時自動創建的,它也可以通過Thead類對象來控制,通過調用CurrentThread方法獲得當前線程的引用

多線程的優勢:進程有獨立的地址空間,同一進程內的線程共享進程的地址空間。啟動一個線程所花費的空間遠遠小于啟動一個進程所花費的空間,而且,線程間彼此切換所需的時間也遠遠小于進程間切換所需要的時間。

二、多線程優點

1、提高應用程序響應。這對圖形界面的程序尤其有意義,當一個操作耗時很長時,整個系統都會等待這個操作,此時程序不會響應鍵盤、鼠標、菜單的操作,而使用多線程技術,將耗時長的操作(time consuming)置于一個新的線程,可以避免這種尷尬的情況。
2、使多CPU系統更加有效。操作系統會保證當線程數不大于CPU數目時,不同的線程運行于不同的CPU上。
3、改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序會利于理解和修改。。

多線程盡管優勢明顯,但是線程并發沖突、同步以及管理跟蹤,可能給系統帶來很多不確定性,這些必須引起足夠重視。

廢話不多說開始我們的多線程之旅。

三、多線程的應用場合:

簡單總結了一下,一般有兩種情況:

1)多個線程,完成同類任務,提高并發性能

2)一個任務有多個獨立的步驟,多個線程并發執行各子任務,提高任務處理效率

四、案例--搬運工

在我們現實生活中,經??吹竭@樣的場景。有一堆貨物,有幾個搬運工負責將貨物搬運到指定地點。但是搬運工能力不同,有人一次能搬多箱,有人走路比較慢,搬運一趟的時間間隔比較長。搬運工,各自搬運,無先后,互不干擾。我們如何在程序中實現這種場景呢?

案例分析:
這個就是最簡單的多線程的實際案例。每個人相當于一個線程,并發執行。當貨物搬運完畢后,每個線程自動停止。這里暫時不考慮死鎖情況。

案例代碼:

復制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace MutiThreadSample.Transport
{
    /// <summary>
    /// 搬運工
    /// </summary>
    public class Mover
    {
        /// <summary>
        /// 總數
        /// </summary>
        public static int GoodsTotal { get; set; }
        /// <summary>
        /// 間隔時間
        /// </summary>
        public static int IntervalTime { get; set; }
        /// <summary>
        /// 名稱
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 單位時間搬運量
        /// </summary>
        public int LaborAmount { get; set; }
        /// <summary>
        /// 搬運
        /// </summary>
        public void Move()
        {
            while (GoodsTotal > 0)
            {
                GoodsTotal -= LaborAmount;
                Console.WriteLine("搬運者:{0} 于 {1} 搬運貨物 {2}",this.Name,DateTime.Now.Millisecond,this.LaborAmount);
                Thread.Sleep(IntervalTime);
                Console.WriteLine("搬運者:{0} Continue",this.Name);
            }
        }
        /// <summary>
        /// 搬運
        /// </summary>
        /// <param name="interval">時間間隔</param>
        public void Move(object interval)
        {
            int tempInterval = 0;
            if (!int.TryParse(interval.ToString(), out tempInterval))
            {
                tempInterval = IntervalTime;
            }           
            while (GoodsTotal > 0)
            {
                GoodsTotal -= LaborAmount;
                Console.WriteLine("搬運者:{0} 于 {1} 搬運貨物 {2}", this.Name, DateTime.Now.Millisecond, this.LaborAmount);
                Thread.Sleep(tempInterval);
            }
        }
     }
}

測試:

復制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace MutiThreadSample.Transport
{
    /// <summary>
    /// 測試搬運
    /// </summary>
    public class TestMove
    {
        /// <summary>
        /// 搬運
        /// </summary>
        public static void Move()
        {
            //測試搬運工
            Mover.GoodsTotal = 200;
            Mover.IntervalTime = 10;
            Mover m1 = new Mover() { Name = "Tom", LaborAmount = 5 };
            Mover m2 = new Mover() { Name = "Jim", LaborAmount = 10 };
            Mover m3 = new Mover() { Name = "Lucy", LaborAmount = 20 };

            List<Mover> movers = new List<Mover>();
            movers.Add(m1);
            //movers.Add(m2);
            //movers.Add(m3);

            if (movers != null && movers.Count > 0)
            {
                foreach (Mover m in movers)
                {                   
                    Thread thread = new Thread(new ThreadStart(m.Move));
                    thread.Start();
                }
            }

            //Main Thread continue
            // validate Thread.Sleep()
            //int i =0;
            //int j = 0;
            //while (i < 10)
            //{
            //    while(j<10000000)
            //    {
            //        j++;               
            //    }
            //    Console.WriteLine("CurrentThread:{0}", Thread.CurrentThread.Name);
            //    i++;
            //}

        }

        /// <summary>
        /// 搬運
        /// </summary>
        public static void MoveWithParamThread()
        {
            //測試搬運工
            Mover.GoodsTotal = 1000;
            Mover.IntervalTime = 100;
            Mover m1 = new Mover() { Name = "Tom", LaborAmount = 5 };
            Mover m2 = new Mover() { Name = "Jim", LaborAmount = 10 };
            Mover m3 = new Mover() { Name = "Lucy", LaborAmount = 20 };

            List<Mover> movers = new List<Mover>();
            movers.Add(m1);
            movers.Add(m2);
            movers.Add(m3);

            if (movers != null && movers.Count > 0)
            {
                foreach (Mover m in movers)
                {
                    Thread thread = new Thread(new ParameterizedThreadStart(m.Move));
                    thread.Start(10);
                }
            }
        }
    }
}

 通過案例我們也接觸了Thread,下面我們將詳細介紹Thread的功能。

五、Thread

 創建并控制線程,設置其優先級并獲取其狀態。

常用方法:

Start()

導致操作系統將當前實例的狀態更改為 ThreadState.Running。

一旦線程處于 ThreadState.Running 狀態,操作系統就可以安排其執行。 線程從方法的第一行(由提供給線程構造函數的 ThreadStart 或 ParameterizedThreadStart 委托表示)開始執行。線程一旦終止,它就無法通過再次調用 Start 來重新啟動。

Thread.Sleep()

調用 Thread.Sleep 方法會導致當前線程立即阻止,阻止時間的長度等于傳遞給 Thread.Sleep 的毫秒數,這樣,就會將其時間片中剩余的部分讓與另一個線程。 一個線程不能針對另一個線程調用 Thread.Sleep。

Interrupt()
中斷處于 WaitSleepJoin 線程狀態的線程。

Suspend和Resume(已過時)
掛起和繼續
在 .NET Framework 2.0 版中,Thread.Suspend 和 Thread.Resume 方法已標記為過時,并將從未來版本中移除。

Abort()
方法用于永久地停止托管線程。一旦線程被中止,它將無法重新啟動。

Join()
阻塞調用線程,直到某個線程終止時為止。

ThreadPriority(優先級)
指定 Thread 的調度優先級。
ThreadPriority 定義一組線程優先級的所有可能值。線程優先級指定一個線程相對于另一個線程的相對優先級。
每個線程都有一個分配的優先級。在運行庫內創建的線程最初被分配 Normal 優先級,而在運行庫外創建的線程在進入運行庫時將保留其先前的優先級。可以通過訪問線程的 Priority 屬性來獲取和設置其優先級。
根據線程的優先級調度線程的執行。用于確定線程執行順序的調度算法隨操作系統的不同而不同。操作系統也可以在用戶界面的焦點在前臺和后臺之間移動時動態地調整線程的優先級。
一個線程的優先級不影響該線程的狀態;該線程的狀態在操作系統可以調度該線程之前必須為 Running。

六、創建線程方式

通過搬運工案例我們能夠了解線程的工作原理,也明白了線程的創建方式。

其實在C#中創建線程有幾種方式,這里給大家舉幾個常用例子,如下:

復制代碼 代碼如下:

using System;
using System.Threading;

namespace MutiThreadSample
{
    /// <summary>
    /// 創建線程的方式
    /// </summary>
    class CreateThread
    {
        /// <summary>
        /// 不帶參數的委托
        /// </summary>
        public void CreateThreadWithThreadStart()
        {
            Thread thread = new Thread(new ThreadStart(ThreadCallBack));
            thread.Start();
        }
        /// <summary>
        /// 帶參數的委托
        /// </summary>
        public void CreateThreadWithParamThreadStart()
        {
            Thread thread = new Thread(new ParameterizedThreadStart(ThreadCallBackWithParam));
            thread.Start();
        }
        /// <summary>
        /// 匿名函數
        /// </summary>
        public void CreateThreadWithAnonymousFunction()
        {
            Thread thread = new Thread(delegate()
            {
                Console.WriteLine("進入子線程1");
                for (int i = 1; i < 4; ++i)
                {
                    Thread.Sleep(50);
                    Console.WriteLine("/t+++++++子線程1+++++++++");
                }
                Console.WriteLine("退出子線程1");
            });
            thread.Start();
        }
        /// <summary>
        /// 直接賦值委托
        /// </summary>
        public void CreateThreadWithCallBack()
        {
            Thread _hThread = new Thread(ThreadCallBack);
            _hThread.Start();

        }
        /// <summary>
        /// 無參數的方法調用
        /// </summary>
        public void ThreadCallBack()
        {
            // Do Something
        }
        /// <summary>
        /// 帶參數的方法
        /// </summary>
        /// <param name="obj"></param>
        public void ThreadCallBackWithParam(object obj)
        {
            // Do Something
        } 
    }
}

時鐘線程

使用 TimerCallback 委托指定希望 Timer 執行的方法。 計時器委托在構造計時器時指定,并且不能更改。 此方法不在創建計時器的線程上執行,而是在系統提供的 ThreadPool 線程上執行。創建計時器時,可以指定在第一次執行方法之前等待的時間量(截止時間)以及此后的執行期間等待的時間量(時間周期)。 可以使用 Change 方法更改這些值或禁用計時器。

復制代碼 代碼如下:

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        // Create an event to signal the timeout count threshold in the
        // timer callback.
        AutoResetEvent autoEvent     = new AutoResetEvent(false);

        StatusChecker  statusChecker = new StatusChecker(10);

        // Create an inferred delegate that invokes methods for the timer.
        TimerCallback tcb = statusChecker.CheckStatus;

        // Create a timer that signals the delegate to invoke
        // CheckStatus after one second, and every 1/4 second
        // thereafter.
        Console.WriteLine("{0} Creating timer./n",
            DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = new Timer(tcb, autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every
        // 1/2 second.
        autoEvent.WaitOne(5000, false);
        stateTimer.Change(0, 500);
        Console.WriteLine("/nChanging period./n");

        // When autoEvent signals the second time, dispose of
        // the timer.
        autoEvent.WaitOne(5000, false);
        stateTimer.Dispose();
        Console.WriteLine("/nDestroying timer.");
    }
}

class StatusChecker
{
    private int invokeCount;
    private int  maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.",
            DateTime.Now.ToString("h:mm:ss.fff"),
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal Main.
            invokeCount  = 0;
            autoEvent.Set();
        }
    }
}



七、前臺線程和后臺線程

.Net的公用語言運行時(Common Language Runtime,CLR)能區分兩種不同類型的線程:前臺線程和后臺線程。這兩者的區別就是:應用程序必須運行完所有的前臺線程才可以退出;而對于后臺線程,應用程序則可以不考慮其是否已經運行完畢而直接退出,所有的后臺線程在應用程序退出時都會自動結束。

一個線程是前臺線程還是后臺線程可由它的IsBackground屬性來決定。這個屬性是可讀又可寫的。它的默認值為false,即意味著一個線程默認為前臺線程。

我們可以將它的IsBackground屬性設置為true,從而使之成為一個后臺線程。下面的例子是一個控制臺程序,程序一開始便啟動了10個線程,每個線程運行5秒鐘時間。由于線程的IsBackground屬性默認為false,即它們都是前臺線程,所以盡管程序的主線程很快就運行結束了,但程序要到所有已啟動的線程都運行完畢才會結束。示例代碼如下例子中的Test()所示

復制代碼 代碼如下:

using System;
using System.Threading;

namespace MutiThreadSample.ThreadType
{
    class ThreadTypeTest
    {
        /// <summary>
        /// 測試前臺線程
        /// </summary>
        public static void Test()
        {
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(new ThreadStart(ThreadFunc));
                thread.Start();
            }
        }
        /// <summary>
        /// 測試后臺線程
        /// </summary>
        public static void TestBackgroundThread()
        {
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(new ThreadStart(ThreadFunc));
                thread.IsBackground = true;
                thread.Start();
            }
        }
        public static void ThreadFunc()
        {
            Thread.Sleep(0);
            DateTime start = DateTime.Now;
            while ((DateTime.Now - start).Seconds < 20);//可以停頓的時間長一點,效果更加明顯
        }
    }
}

接下來我們對上面的代碼進行略微修改,將每個線程的IsBackground屬性都設置為true,則每個線程都是后臺線程了。那么只要程序的主線程結束了,整個程序也就結束了。示例代碼如代碼中的TestBackgroundThread()。

這個例子直接創建一個控制臺程序即可檢驗。

前臺和后臺線程的使用原則

既然前臺線程和后臺線程有這種差別,那么我們怎么知道該如何設置一個線程的IsBackground屬性呢?下面是一些基本的原則:對于一些在后臺運行的線程,當程序結束時這些線程沒有必要繼續運行了,那么這些線程就應該設置為后臺線程。比如一個程序啟動了一個進行大量運算的線程,可是只要程序一旦結束,那個線程就失去了繼續存在的意義,那么那個線程就該是作為后臺線程的。而對于一些服務于用戶界面的線程往往是要設置為前臺線程的,因為即使程序的主線程結束了,其他的用戶界面的線程很可能要繼續存在來顯示相關的信息,所以不能立即終止它們。這里我只是給出了一些原則,具體到實際的運用往往需要編程者的進一步仔細斟酌。 

八、總結

這一章主要介紹多線程技術的基本知識。涉及多線程的具體應用,包括預防死鎖、線程同步、線程池等,在今后的文章會涉及到。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
丝袜美腿精品国产二区| 日韩av电影手机在线观看| 亚洲高清不卡av| 久久99国产综合精品女同| 欧美日韩国产麻豆| 国产美女精品免费电影| 亚洲香蕉av在线一区二区三区| 国产91精品网站| 亚洲精品不卡在线| 久久精品视频免费播放| 久久久免费电影| 一本色道久久88综合亚洲精品ⅰ| 久久久久久亚洲精品| 最近的2019中文字幕免费一页| 久久久久久亚洲精品中文字幕| 91精品视频一区| 4k岛国日韩精品**专区| 国产亚洲精品激情久久| www国产精品视频| 国产一区二区在线免费| 91成人在线观看国产| 欧美一级视频在线观看| 亚洲国产精品高清久久久| 91高潮精品免费porn| 国产精品中文在线| 欧美激情在线观看视频| 91丝袜美腿美女视频网站| 久久九九全国免费精品观看| 国内外成人免费激情在线视频网站| 岛国av午夜精品| 97在线免费视频| 国产精品丝袜白浆摸在线| 欧美裸体xxxx极品少妇| 亚洲国产精彩中文乱码av| 欧美国产日韩xxxxx| 久久久久久久电影一区| 国产精品视频免费观看www| 欧美成人午夜激情在线| 久久久久久久91| 日本精品视频网站| 欧洲亚洲女同hd| 欧美一区二粉嫩精品国产一线天| 欧美刺激性大交免费视频| 国产欧美日韩高清| 成人淫片在线看| 日韩成人中文字幕在线观看| 欧美与黑人午夜性猛交久久久| 国产一区二区成人| 亚洲一区二区免费在线| 日韩美女主播视频| 日韩av男人的天堂| 伊人精品在线观看| 国产精品白丝jk喷水视频一区| 川上优av一区二区线观看| 欧美精品久久久久久久久久| 日本sm极度另类视频| 久久久精品一区二区| 国内精品久久久久久影视8| 亚洲电影免费观看高清完整版在线观看| 亚洲成人黄色网址| 久久99精品国产99久久6尤物| 亚洲综合日韩中文字幕v在线| 欧美激情免费在线| 亚洲国产日韩欧美综合久久| 欧美精品在线免费| 欧美成人网在线| 欧美激情欧美狂野欧美精品| 欧美一级大片在线观看| 欧美中文在线观看| 琪琪亚洲精品午夜在线| 亚洲一区二区久久久久久久| 一道本无吗dⅴd在线播放一区| 国产成人免费av| 欧美一级黄色网| 九九精品在线播放| 国产精品久久久久久超碰| 宅男66日本亚洲欧美视频| 国产精品69精品一区二区三区| 91精品在线播放| 亚洲免费av电影| 色妞欧美日韩在线| 中文字幕国产亚洲2019| 亚洲精品自拍偷拍| 欧美色视频日本版| 欧美大片第1页| 国产成人jvid在线播放| 日韩美女毛茸茸| 91精品国产一区| 国模精品视频一区二区三区| 麻豆国产精品va在线观看不卡| 国产精品女主播| 日韩中文字幕av| 日韩欧美高清在线视频| 一本色道久久88综合日韩精品| 成人国产亚洲精品a区天堂华泰| 欧美电影在线观看完整版| 成人观看高清在线观看免费| 日韩成人av一区| 成人免费福利视频| 久久久久久久网站| 欧美疯狂xxxx大交乱88av| 久久久久久久爱| 91欧美激情另类亚洲| 亚州成人av在线| 在线播放日韩av| 国产在线精品自拍| 日韩欧美亚洲国产一区| 国产精品99久久久久久人| 成人性生交xxxxx网站| 亚洲精品福利资源站| 亚洲aaa激情| 亚洲精品自拍视频| 亚洲的天堂在线中文字幕| 中文字幕亚洲欧美日韩在线不卡| 日韩视频精品在线| 456国产精品| 97在线观看视频| 久久天天躁狠狠躁夜夜躁2014| 日韩av免费在线播放| 国内精品久久久久久影视8| 国内精久久久久久久久久人| 欧美精品第一页在线播放| 欧美多人乱p欧美4p久久| 国产欧美精品va在线观看| 成人美女av在线直播| 欧美午夜宅男影院在线观看| 91热福利电影| 亚洲视频日韩精品| 久久久久国色av免费观看性色| 日韩电影免费在线观看中文字幕| 午夜剧场成人观在线视频免费观看| 亚洲人精品午夜在线观看| 精品久久久久国产| 久久久999精品免费| 亚洲欧美在线x视频| 亚洲视频777| 国产999视频| 国产婷婷97碰碰久久人人蜜臀| 日韩视频欧美视频| 亚洲视频在线看| 国产日产亚洲精品| 黄色一区二区三区| 久久精品欧美视频| 国产视频亚洲视频| 日韩精品一区二区视频| 日韩欧美国产视频| 亚洲国产99精品国自产| 国产欧美亚洲精品| 欧美日韩国产在线看| 日韩在线www| 亚洲欧美日韩第一区| 日本高清+成人网在线观看| 亚洲新声在线观看| 欧美日韩免费区域视频在线观看| 91人人爽人人爽人人精88v| 欧美日韩一区免费| 97视频免费在线看| 久久精品视频99| 日韩av观看网址| 国产精品久久久久久久久久尿| 欧美精品xxx| 日韩暖暖在线视频| 美日韩丰满少妇在线观看| xxx成人少妇69|