C# 中多線程的應用

來源:互聯網
上載者:User

 1.使用線程的情況
    ①.程式需要執行和兩個和多個任務
   ②.程式要等待某事件的發生:例如使用者輸入、檔案操作、網路操作和搜尋
   ③.背景程式

2.多線程的並發執行
如果有多個線程在執行,單CPU只有一個,到底執行的哪個?
①.如果一個線程連續佔用CPU資源時間過長,其它的資源得不到執行,
     則系統會強制的切換執行其它線程。(強制剝奪)
②.如果一個線程沒事可做、CPU可執行其它線程。(主動放棄)
③.這是由作業系統的調度機制決定的,不同的作業系統調度機制不一樣。
   一般無法精確的預料多線程的執行順序,在程式設計的時候應特別注意

3.建立並啟動線程
ThreadStart 線程啟動委託名=new ThreadStart(方法名);
Thread 線程執行個體名=new Thread(線程啟動委託名);
線程執行個體名.Start();

4.終止線程
①.線程執行個體名.Abort();用此方法的後果是不可恢複的終止線程。
②.線程執行個體名.Interrupt();中斷後可恢複

5.休眠線程
①.線程執行個體名.Sleep();
    當線程Sleep時,系統就立即退出執行隊列一段時間,當睡眠結束時,系統會產生一個時鐘中斷,從而
    使線程回到執行隊列中,從而恢複線程的執行。

6.掛起/恢複線程
①.線程執行個體名.Suspend();掛起
    與線程休眠不同,線程的掛起不會使線程立即停止執行,直到線程到達安全點之後它才可以將該

     線程掛起,如果線程尚未啟動或已經停止,則它將不能掛起。
②.線程執行個體名.Resume();恢複
     將使一個線程跳出掛起狀態並使該線程繼續執行。
    一個線程不能對另一個線程調用Sleep() ,但是一個線程可以對另一個線程調用Suspend()。
    還可以使用許多其它的方式來阻塞線程。例如,可以通過調用 Thread.Join 使一個線程等待另一個線程 (子線程)停止。使用Monitor.Wait使一個線程等待訪問一個同步對象。

7.序列化線程
①.線程執行個體名.jion();
    例如在主線程中插入t.jion();
     主線程執行到這條語句後,主線程(當前線程)立即進入阻塞狀態.直到t運行完後阻塞狀態才解除。

    相當於把t的任務插入或串聯到主線程中,把兩條線索串聯成一條線索

8.線程的鎖定機制
線程的鎖定機制可以保證每次只有一個線程可以訪問共用資源。
使用關鍵字lock
①.lock語句的文法
     lock(對象引用)語句塊;
②.lock語句的功能
     當對象被lock 鎖定時,訪問該線程的其它線程會進入等待的狀態。
③.對象鎖機制保證了對象訪問的完整性:只有一個線程完成操作後,其它的線程才能進行操作。
④.一般情況下,當一個線程寫某個變數,而同時可能有其它的線程讀或寫這個變數時,為了保持資料的一  

    致性應該使用鎖定機制。
⑤.線程的安全性
     執行緒安全性就是保護的類的成員和代碼的安全,從而使他們不會同時被幾個線程中斷,使用鎖定機制。
⑥.多線程公用一個對象時,就不應該使用lock關鍵字了,這裡Monitor,Monitor提供了使線程共用資源的方 案。
Monitor類可以鎖定一個對象,一個線程只有得到這把鎖才可以對該對象進行操作。
如:
Monitor.Enter(obj);
Monitor.Exit(obj);
⑦.臨界區和鎖
當談論多線程應用程式的時候,首先應該想到的就是並發性問題。儘管這對於同時執行多個任務的程式是很有用的,但通常都是危險的。為瞭解決這個問題,在C#中提出了臨界區和鎖的概念。在程式設計中,臨界區是一塊在任何時候只能有一個進程進入的地區。在C#中通過語句lock來聲明臨界區。lock聲明後面的代碼,不管是以行還是一塊代碼,在同一時間最多隻能有一個進程執行。

9.線程的優先順序具有不可靠性,就是說不能用優先順序來控制線程的執行順序。

10.後台線程
   ①.什麼是後台線程?比起應用程式的主圖形化使用者介面(GUI)線程來說,這些線程以較低的優先權在不同的過程中

   運行著。對於不能立即執行結束, 又不想一直等待的任務,後台線程能很好的勝任。在C#中,把線程對象的      

   IsBackground屬性設為true,該線程即為後台線程。
   後台線程跟前台線程只有一個區別,那就是後台線程不妨礙程式的終止。一旦一個進程所有的前台線程都終止後,

   CLR將通過調用任意一個存活中的後台進程的Abort()方法來徹底終止進程。

  注意:後台線程不能直接操作所在進程之外的資料引用。

  ②.怎樣與後台線程通訊?運用MethodInvoker委派實體。

  要使用MethodInvoker委派,需要三個條件:

  a.一個建立委派的後台線程

  Thread thread=new Thread(new ThreadStart(Run));

  thread.IsBackground=true;//把Thread設為後台線程

  thread.Start();

  b.一個用作後台線程與前台可視化單元的介面的類級方法

  public void Run()
  {
int count=0;
    try
    {
      MethodInvoker mi=new MethodInvoker(this.UpdateLabel);
   //建立一個委託,UpdateLabel是該委託所託管的代碼,必須是聲明為void 且不接受任何參數的任何方法。
      while(true)
      {
        count++;
   //this.Invoke(mi);//同步執行委託
        this.BeginInvoke(mi);//非同步執行委託
        Thread.Sleep(500);
      }
    }
    catch(ThreadInterruptedException e)
    {
      Console.WriteLine("Interruption Exception in Thread:{0}",e);
    }
    catch(Exception ex)

    {
      Console.WriteLine("Exception in Thread:{0}",ex);
    }
  }

  c.一個應用程式中可以更新的可視化單元
  public void UpdateLabel()
  {
    label1.Text=count.ToString();
  }

例1:使用多線程實現的打字練習(VS2005)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
/*
* 編寫一個基於Windows表單的應用程式,實現打字練習功能,要使用多線程,在主線程裡用
* Timer控制項定時產生Label控制項,每個Label控制項顯示一個隨機產生的字母,每產生一個Label
* 就新開一個線程(輔助線程),這個線程用於控制Label控制項的向下移動,主線程監視鍵盤
* 輸入,如果鍵盤輸入文本與這個Label控制項的Text相同,Label就消失
*/
namespace TypewriteExcercise
{
    public partial class frmTyped : Form
    {

        public frmTyped()
        {
            InitializeComponent();
        }

        private void frmTyped_Load(object sender, EventArgs e)
        {
           timer1.Start();//啟動時鐘
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Label label = new Label();//建立標籤對象
          
            label.Width = 12;
            label.Height = 12;
            label.ForeColor = Color.White;//把標籤的前景色彩設為白色
            label.BackColor = this.BackColor;//把表單的背景色設定黑色為標籤的背景色
            this.Controls.Add(label);//把標籤添加到表單中
            System.Random random = new Random(DateTime.Now.Second * DateTime.Now.Second);

            //當前系統時間的秒數的平方作為隨機種子
            label.Left = random.Next(this.Width);//標籤隨機數[0,表單的寬度),

            Letter letter = new Letter(label, this);//把標籤和表單傳遞給letter對象
            ThreadStart threadstart = new ThreadStart(letter.Run);//建立線程啟動委託,注意括弧裡面是方法名
            Thread thread = new Thread(threadstart);//建立線程執行個體
            thread.Start();//啟動線程
        }

        private void frmTyped_KeyPress(object sender, KeyPressEventArgs e)
        {
            foreach(Label label in this.Controls)
            {
                if(label==null)//沒有標籤
                {
                    break;//退出
                }
                if(label.Text[0]==e.KeyChar)
                //label.Text返回的是字串,label.Text[0]返回第一個字元。e.KeyChar返回的是字元。這樣都為字元才能判斷
                {
                    label.Dispose();//釋放由label所使用的所有資源
                    this.Controls.Remove(label);//從frmTyped中移除label
                }
            }
        }

    }
    public class Letter
    {
        private Label _label;
        private Form _container;
        private int _speed = 2;
        public Letter(Label label, Form container) //建構函式接受標籤和表單
        {
            _label = label;//初始化標籤
            _container = container;//初始化表單

            Random random = new Random(DateTime.Now.Second);//使用當前系統時間的秒數作為隨機種子
            _speed = random.Next(5) + 1;//產生一個[1,6)的隨機數用來表示速度

            _label.Text = Convert.ToChar(65 + random.Next(57)).ToString();
            /*
             * a-z的ASCII碼97-122 A-Z 的ASCII碼65-90 [:91   /:92 ]:93 ^:94 _:95   `:96
             */
            switch(_speed)
            {
                case 1:
                    _label.ForeColor = Color.Red;//將標籤的前景色彩設為紅色
                    break;
                case 2:
                    _label.ForeColor = Color.Yellow;
                    break;
                case 3:
                    _label.ForeColor = Color.Blue;
                    break;
                case 4:
                    _label.ForeColor = Color.Green;
                    break;
                case 5:
                    _label.ForeColor = Color.White;
                    break;
                default:
                    _label.ForeColor = Color.White;
                    break;

            }
        }
        public void Run()
        {
            try
            {
                while (_label.Top <= this._container.Height + 100)//標籤的的上邊距小於或等於表單的高度+100像素
                {
                    if (_label == null)//沒有產生標籤這種情況
                    {
                        Thread.CurrentThread.Abort();//就終止當前的線程
                    }
                    _label.Top += 1;//有標籤,上邊距就加1像素;
                    Thread.Sleep(_speed * 5);//讓線程休眠(速度越快,休眠的時間越短。以毫秒為單位);
                }
                if(Thread.CurrentThread.IsAlive)//如果當前線程還是存活的
                {
                    Thread.CurrentThread.Abort();//就終止當前的線程
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("錯誤:" + ex.Message);//擷取描述當前異常的訊息
                Console.WriteLine("錯誤:" + ex.StackTrace);//擷取當前異常發生時呼叫堆疊上的幀的字串表達形式
            }
            finally //釋放資源,不管是否發生異常,finally都要五條件的執行
            {
                if(!_label.Disposing)//如果標籤沒有釋放到進程中
                {
                    _label.Dispose();//釋放由標籤使用的所有資源
                }
                _container.Controls.Remove(_label);//移除在表單中產生的所有標籤
            }
        }
    }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.