a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁(yè) > 編程 > C# > 正文

淺解關(guān)于C#多線程的介紹

2020-01-24 03:28:08
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

多線程的相關(guān)概念
--------------------------------------------------------------------------------
1.進(jìn)程:是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ);是一個(gè)正在執(zhí)行的程序;計(jì)算機(jī)中正在運(yùn)行的程序?qū)嵗豢梢苑峙浣o處理器并由處理器執(zhí)行的一個(gè)實(shí)體;由單一順序的執(zhí)行顯示,一個(gè)當(dāng)前狀態(tài)和一組相關(guān)的系統(tǒng)資源所描述的活動(dòng)單元。
2.線程:線程是程序中一個(gè)單一的順序控制流程。是程序執(zhí)行流的最小單元。另外,線程是進(jìn)程中的一個(gè)實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。一個(gè)線程可以創(chuàng)建和撤消另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。由于線程之間的相互制約,致使線程在運(yùn)行中呈現(xiàn)出間斷性。線程也有就緒、阻塞和運(yùn)行三種基本狀態(tài)。每一個(gè)程序都至少有一個(gè)線程,若程序只有一個(gè)線程,那就是程序本身。
3.多線程:在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱(chēng)為多線程。
--------------------------------------------------------------------------------
小結(jié):其實(shí)更容易理解一點(diǎn)進(jìn)程與線程的話,可以舉這樣一個(gè)例子:把進(jìn)程理解成為一個(gè)運(yùn)營(yíng)著的公司,然而每一個(gè)公司員工就可以叫做一個(gè)進(jìn)程。每個(gè)公司至少要有一個(gè)員工,員工越多,如果你的管理合理的話,公司的運(yùn)營(yíng)速度就會(huì)越好。這里官味一點(diǎn)話就是說(shuō)。cpu大部分時(shí)間處于空閑時(shí)間,浪費(fèi)了cpu資源,多線程可以讓一個(gè)程序“同時(shí)”處理多個(gè)事情,提高效率。
--------------------------------------------------------------------------------
單線程問(wèn)題演示
--------------------------------------------------------------------------------
創(chuàng)建一個(gè)WinForm應(yīng)用程序,這里出現(xiàn)的問(wèn)題是,點(diǎn)擊按鈕后如果在彈出提示框之前,窗體是不能被拖動(dòng)的。

復(fù)制代碼 代碼如下:

private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10000000000; i++) 
            {
                i += 1;
            }
            MessageBox.Show("出現(xiàn)后能拖動(dòng),提示沒(méi)出現(xiàn)之前窗體不能被拖動(dòng)");
        }

原因:運(yùn)行這個(gè)應(yīng)用程序的時(shí)候,窗體應(yīng)用程序自帶一個(gè)叫做UI的線程,這個(gè)線程負(fù)責(zé)窗體界面的移動(dòng)大小等。如果點(diǎn)擊按鈕則這個(gè)線程就去處理這個(gè)循環(huán)計(jì)算,而放棄了其它操作,故而窗體拖動(dòng)無(wú)響應(yīng)。這就是單線程帶來(lái)的問(wèn)題。

解決辦法:使用多線程,我們自己創(chuàng)建線程。把計(jì)算代碼放入我們自己寫(xiě)的線程中,UI線程就能繼續(xù)做他的界面響應(yīng)了。
--------------------------------------------------------------------------------
線程的創(chuàng)建
--------------------------------------------------------------------------------

 線程的實(shí)現(xiàn):線程一定是要執(zhí)行一段代碼的,所以要產(chǎn)生一個(gè)線程,必須先為該線程寫(xiě)一個(gè)方法,這個(gè)方法中的代碼,就是該線程中要執(zhí)行的代碼,然而啟動(dòng)線程時(shí),是通過(guò)委托調(diào)用該方法的。線程啟動(dòng)是,調(diào)用傳過(guò)來(lái)的委托,委托就會(huì)執(zhí)行相應(yīng)的方法,從而實(shí)現(xiàn)線程執(zhí)行方法。

復(fù)制代碼 代碼如下:

//創(chuàng)建線程 
        private void button1_Click(object sender, EventArgs e)
        {
            //ThreadStart是一個(gè)無(wú)參無(wú)返回值的委托。
            ThreadStart ts = new ThreadStart(js);
            //初始化Thread的新實(shí)例,并通過(guò)構(gòu)造方法將委托ts做為參數(shù)賦初始值。
            Thread td = new Thread(ts);   //需要引入System.Threading命名空間
            //運(yùn)行委托
            td.Start();
        }
        //創(chuàng)建的線程要執(zhí)行的函數(shù)。
        void js()
        {
            for (int i = 0; i < 1000000000; i++)
            {
                i += 1;
            }
            MessageBox.Show("提示出現(xiàn)前后窗體都能被拖動(dòng)");
        }

把這個(gè)計(jì)算寫(xiě)入自己寫(xiě)的線程中,就解決了單線程中的界面無(wú)反應(yīng)缺陷。
--------------------------------------------------------------------------------
小結(jié):創(chuàng)建線程的4個(gè)步驟:1.編寫(xiě)線程索要執(zhí)行的方法。2.引用System.Threading命名空。3.實(shí)例化Thread類(lèi),并傳入一個(gè)指向線程所要運(yùn)行方法的委托。4.調(diào)用Start()方法,將該線程標(biāo)記為可以運(yùn)行的狀態(tài),但具體執(zhí)行時(shí)間由cpu決定。
--------------------------------------------------------------------------------
 方法重入(多個(gè)線程執(zhí)行一個(gè)方法)
--------------------------------------------------------------------------------
 由于線程可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。

所以多個(gè)線程同時(shí)執(zhí)行一個(gè)方法的情況是存在的,然而這里不經(jīng)過(guò)處理的話會(huì)出現(xiàn)一點(diǎn)問(wèn)題,線程之間先后爭(zhēng)搶資源,致使數(shù)據(jù)計(jì)算結(jié)果錯(cuò)亂。

復(fù)制代碼 代碼如下:

public partial class 方法重入 : Form
    {
        public 方法重入()
        {
            InitializeComponent();

            //設(shè)置TextBox類(lèi)的這個(gè)屬性是因?yàn)椋_(kāi)啟ui線程,
            //微軟設(shè)置檢測(cè)不允許其它線程對(duì)ui線程的數(shù)據(jù)進(jìn)行訪問(wèn),這里我們把檢測(cè)關(guān)閉,也就允許了其它線程對(duì)ui線程數(shù)據(jù)的訪問(wèn)。
            //如果檢測(cè)不設(shè)置為False,則報(bào)錯(cuò)。
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "0";
            //開(kāi)啟第一個(gè)線程,對(duì)js方法進(jìn)行計(jì)算
            ThreadStart ts = new ThreadStart(js);
            Thread td = new Thread(ts);
            td.Start();

            //開(kāi)啟第二個(gè)線程,對(duì)js方法進(jìn)行計(jì)算
            ThreadStart ts1 = new ThreadStart(js);
            Thread td1 = new Thread(ts1);
            td1.Start();
        }
        //多線程要重入的方法。
        void js()
        {
            int a = Convert.ToInt32(textBox1.Text);
            for (int i = 0; i < 2000; i++)
            {
                a++;
                textBox1.Text = a.ToString();
            }
        }
    }


出錯(cuò)現(xiàn)象:點(diǎn)擊按鈕后TextBox1中數(shù)據(jù)為2000+或2000,如果你看到的數(shù)據(jù)一直是2000說(shuō)明你的計(jì)算機(jī)cpu比較牛X,這樣的話你想看到不是2000的話,你可以多點(diǎn)擊幾次試試,真不行的話,代碼中給TextBox1賦值為0,換做在界面中給textBox1數(shù)值默認(rèn)值為0試試看。

出錯(cuò)原因:兩個(gè)進(jìn)程同時(shí)計(jì)算這個(gè)方法,不相干擾應(yīng)該每個(gè)線程計(jì)算的結(jié)果都是2000的,但是這里的結(jié)果輸出卻讓人以外,原因是第一個(gè)兩個(gè)線程同時(shí)計(jì)算,并不是同時(shí)開(kāi)始計(jì)算,而是根據(jù)cpu決定的哪個(gè)先開(kāi)始,哪個(gè)后開(kāi)始,雖然相差時(shí)間不多,但后開(kāi)始的就會(huì)取用先開(kāi)始計(jì)算過(guò)的數(shù)據(jù)計(jì)算,這樣就會(huì)導(dǎo)致計(jì)算錯(cuò)亂。

解決辦法:解決這個(gè)的一個(gè)簡(jiǎn)單辦法解釋給方法加鎖,加鎖的意思就是第一個(gè)線程取用過(guò)這個(gè)資源完畢后,第二個(gè)線程再來(lái)取用此資源。形成排隊(duì)效果。

下面給方法加鎖。

復(fù)制代碼 代碼如下:

//多線程要重入的方法,這里加鎖。
        void js()
        {
            lock (this)
            {
                int a = Convert.ToInt32(textBox1.Text);
                for (int i = 0; i < 2000; i++)
                {
                    a++;
                    textBox1.Text = a.ToString();
                }
            }
        }

給方法加過(guò)鎖后,線程一前一后取用資源,就能避免不可預(yù)計(jì)的錯(cuò)亂結(jié)果,第一個(gè)線程計(jì)算為2000,第二個(gè)線程計(jì)算就是從2000開(kāi)始,這里的結(jié)果就為4000。
--------------------------------------------------------------------------------
小結(jié):多線程可以同時(shí)運(yùn)行,提高了cpu的效率,這里的同時(shí)并不是同時(shí)開(kāi)始,同時(shí)結(jié)束,他們的開(kāi)始是由cpu決定的,時(shí)間相差不大,但會(huì)有不可預(yù)計(jì)的計(jì)算錯(cuò)亂,這里要注意類(lèi)似上面例子導(dǎo)致的方法重入問(wèn)題。
--------------------------------------------------------------------------------
 前臺(tái)線程后臺(tái)線程
--------------------------------------------------------------------------------
 .Net的公用語(yǔ)言運(yùn)行時(shí)能區(qū)分兩種不同類(lèi)型的線程:前臺(tái)線程和后臺(tái)線程。這兩者的區(qū)別就是:應(yīng)用程序必須運(yùn)行完所有的前臺(tái)線程才可以退出;而對(duì)于后臺(tái)線程,應(yīng)用程序則可以不考慮其是否已經(jīng)運(yùn)行完畢而直接退出,所有的后臺(tái)線程在應(yīng)用程序退出時(shí)都會(huì)自動(dòng)結(jié)束。

問(wèn)題:關(guān)閉了窗口,消息框還能彈出。

復(fù)制代碼 代碼如下:

private void button1_Click(object sender, EventArgs e)
        {
            //開(kāi)啟一個(gè)線程,對(duì)js方法進(jìn)行計(jì)算
            ThreadStart ts2 = new ThreadStart(js);
            Thread td2 = new Thread(ts2);            
            td2.Start();

        }       
        void js()
        {
            for (int i = 0; i < 2000000000; i++)  //如果看不出效果這里的2后面多加0
            {
                i++;
            }
            MessageBox.Show("關(guān)閉了窗口我還是要出來(lái)的!");
        }


原因:.Net環(huán)境使用Thread建立線程,線程默認(rèn)為前臺(tái)線程。即線程屬性IsBackground=false,而前臺(tái)線程只要有一個(gè)在運(yùn)行則應(yīng)用程序不關(guān)閉,所以知道彈出消息框后應(yīng)用程序才算關(guān)閉。

解決辦法:在代碼中設(shè)置td2.IsBackground=true;
--------------------------------------------------------------------------------
 線程執(zhí)行帶參數(shù)的方法
--------------------------------------------------------------------------------

復(fù)制代碼 代碼如下:

//創(chuàng)建一個(gè)執(zhí)行帶參數(shù)方法的線程
        private void button1_Click(object sender, EventArgs e)
        {
            //ParameterizedThreadStart這是一個(gè)參數(shù)類(lèi)型為object的委托
            ParameterizedThreadStart pts=new ParameterizedThreadStart(SayHello);
            Thread td2 = new Thread(pts);
            td2.Start("張三");  //參數(shù)值先入這里
        }
        void SayHello(object name)
        {
            MessageBox.Show("你好,"+name.ToString()+"!");
        }

 線程執(zhí)行帶多參數(shù)的方法
--------------------------------------------------------------------------------
 其實(shí)還是帶一參數(shù)的方法,只不過(guò)是利用參數(shù)類(lèi)型為object的好處,這里將類(lèi)型傳為list類(lèi)型,貌似多參。
復(fù)制代碼 代碼如下:

 //創(chuàng)建一個(gè)執(zhí)行帶多個(gè)參數(shù)的方法線程
        private void button1_Click(object sender, EventArgs e)
        {
            List<string> list = new List<string> { "張三", "李四", "王五" };
            //ParameterizedThreadStart這是一個(gè)參數(shù)類(lèi)型為object的委托
            ParameterizedThreadStart pts=new ParameterizedThreadStart(SayHello);
            Thread td2 = new Thread(pts);
            td2.Start(list);  //參數(shù)值先入這里
        }
        void SayHello(object list)
        {
            List<string> lt = list as List<string>;
            for (int i = 0; i < lt.Count; i++)
            {
                MessageBox.Show("你好," + lt[i].ToString() + "!");
            }
        }

總結(jié):看到這里相信對(duì)多線程應(yīng)該有一個(gè)初步的了解了,我就不說(shuō)了。

 

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产精品视频一区二区三区四区五区 | 狠狠操夜夜操 | 国产一页| 中文字幕日本一区 | 成人在线看片 | 欧美天堂在线观看 | 毛片国产 | 国产在线一区二区三区 | 色玖玖综合 | 国产不卡一区 | 中文字幕在线一区 | 日本视频不卡 | 久久精品国产亚洲精品 | 国产在线观看一区二区三区 | 国产欧美日本 | 吊视频一区二区三区 | 亚洲精品久久久日韩美女极品合集下载 | 91精品久久久久久久久久 | 精品久久久久久久人人人人传媒 | 欧美午夜一区二区三区免费大片 | 色婷婷一区二区三区 | 亚洲欧美日韩另类精品一区二区三区 | av网站免费在线 | 久久综合精品视频 | 国产精品国产成人国产三级 | 久久99精品久久久久久琪琪 | 欧美日韩黄色一级片 | 免费国产在线视频 | 波多野结衣一区三区 | 国产精品一区二区三区麻豆 | 欧美久久一区二区三区 | 青草福利| 久久精品网 | 日韩精品一区二区三区 | 91久久精品国产91久久 | 欧美视频网站 | 欧美日本韩国一区二区 | 欧美淫视频 | 色综合久久伊人 | 久久久男人天堂 | 在线第一页 |