程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 線程,委托和同步的技術理順

線程,委托和同步的技術理順

編輯:C#入門知識

多線程的實現
1、多線程的實現方式
       (一):異步委托(本質是微軟會創建一個執行任務的線程,是使用線程池來完成異步任務),實現異步委托的技術大概有三種,投票、等待句柄、異步回調。
       1、投票:
              public delegate int TakesAWhileDelege(int ms);

        static void Main(string[] args)

        {

            TakesAWhileDelege dl=TakesAWhile;

            IAsyncResult ar = dl.BeginInvoke(1000,null,null);

            while (ar.IsCompleted)

                Console.WriteLine("委托執行完成");

        }

        public static int TakesAWhile(int ms)

        {

            Thread.Sleep(50);

            return ms;

        }

2、等待句柄(通過AsyncWaitHandle獲取委托的等待句柄WaitHandle,通過該句柄的方法WaitOne方法,即阻止當前線程50毫秒,如果超過50毫秒後該委托還沒有完成就返回false)
              public delegate int TakesAWhileDelege(int ms);

        static void Main(string[] args)

        {

            TakesAWhileDelege dl = TakesAWhile;

            IAsyncResult ar = dl.BeginInvoke(1000, null, null);

            while (true)

            {

                if (ar.AsyncWaitHandle.WaitOne(50, false))

                    break;

            }

            int result = dl.EndInvoke(ar);

        }

        public static int TakesAWhile(int ms)

        {

            Thread.Sleep(50);

            return ms;

        }

3、異步回調,(t通過BeginInvoke的最後兩個參數,一個是回調函數,一個是)
             

public delegate int TakesAWhileDelege(int ms);

        static void Main(string[] args)

        {

            TakesAWhileDelege dl = TakesAWhile;

            dl.BeginInvoke(1000, completeTake, dl);

           Console.WriteLine("adfa");

 

        }

        public static void completeTake(IAsyncResult ar)

        {

           

//如果 dl.BeginInvoke(1000, completeTake, dl);中的dl是任何一個參數比如2000,那麼這裡獲取就是

            //int num = (int)ar.AsyncState;
            TakesAWhileDelege dlTemp = ar.AsyncState as TakesAWhileDelege;

           int result= dlTemp.EndInvoke(ar);

        }

        public static int TakesAWhile(int ms)

        {

            Thread.Sleep(50);

            return ms;

        }



       (二):用Thread類創建線程(無參和有參,另外傳遞參數的另一種方法是構建一個類對象,參數作為類對象的成員,然後定義一個threadClass3方法,用於在構造Thread對象的時候傳遞在如:Thread thread2 = new Thread(threadClass3))
       我先聲明,用Thread類聲明的線程默認都是前台線程,即及時main函數執行完畢後,只要有一個前台線程沒有完畢,都會不會終止進程,除非你把IsBackground 改為true,改完後則主線程結束,後台線程也跟著結束,不論他有沒有執行完畢
       1、普通有參和無參
              static void Main(string[] args)

        {

            Thread thread1 = new Thread(threadClass1) { Name = "11", IsBackground = false };

            thread1.Start();

            Thread thread2 = new Thread(threadClass2) { IsBackground = true };

            thread2.Start(100);

        }

        static void threadClass1()

        {

        }

        static void threadClass2(object num)

        {

            int nums = (int)num;

        }

    2、通過構建類對象
    public class Mythread
    {

Private int num;
    public void Mythread(int num)
{

This.num=num;
}

Public void threadClass3()

{

//xxxxxxxxxxxxxxxxxxx

}
}
調用線程的時候,
Mythread my1=new Mythread(100);
Thread th1=new Thread(my1.threadClass3);

3、 thread1.Join();
        Join:是值阻塞這個thread1進程,一直等待這個進程完成後,才繼續往下執行
    thread1.Abort();
        Abort:是終止線程

(三):線程池(線程池中的線程必須是後台線程,線程池的進程只能用於時間較短的任務,長時間的線程的話最好新建一個線程)
              1、沒有參數
        static void Main(string[] args)

        {

            for (int i = 0; i <= 5; i++)

                ThreadPool.QueueUserWorkItem(threadClass);

            Console.ReadLine();

        }

        static void threadClass(object num)

        {

            Thread.Sleep(3000);

            Console.WriteLine(Thread.CurrentThread.ManagedThreadId );

        }
        2、有參數
    構建一個類,參數作為類的成員
      public class MythreadA

    {

      private int num=100;

        public MythreadA(int numS)

      {

          this.num = numS;

      }

      public void threadClass3(object N)

      {

          Thread.Sleep(3000);

          Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + num);

        }

    }
用線程池

static void Main(string[] args)

        {

            for (int i = 0; i <= 5; i++)

            {

                MythreadA Mythread1 = new MythreadA(100+i);

                //QueueUserWorkItem需要一個WaitCallback委托作為參數,該委托必須要一個object類型參數,如果我們需要傳遞參數,可以新建一個類。。

                ThreadPool.QueueUserWorkItem(Mythread1.threadClass3);

               

            }

            Console.ReadLine();

        }

 

2、同步的實現方式
上面說的都是異步的實現,事實上有時候我們也需要不同線程共享文件或者數據,這就需要保證一次只能一個線程訪問和改變共享的狀態,所以這就要用到同步技術
多線程同步技術有:
lock
Monitorlock被編譯器解析為Monitor)、MutexSemaphore

比如:對於同一個對象,我遍歷出20個進程,都把該對象傳遞過去,對該對象的成員num做循環5000次加1操作,此時會出現的問題是,當第一個線程的i等於2000,判斷<5000可以進入循環體的時候,突然線程給了第二個線程,第二個線程繼續執行它上次在i=1的時候暫停的操作,這時i突然變成2000,相當於少加了1999次。。如果經常發生這種情況,最後的20個線程的總的結果必定小於10000

Lock
(鎖定)
private object o=new object
for(int i=0;i<5000;i++)
{
       lock(object )
       {
              num++;
       }
}

Monitor
private object o=new object

lock
被編譯器解析為MonitorMonitor調用Enterobject )方法,讓線程一直等待,直到當前線程被對象鎖定,才開始操作,當然不管是運行結束還是觸發異常,我們都必須調用Exitobject )方法,當然Monitor優於lock的地方在於他可以設置等待鎖定時間,即TryEnter方法
例如,設置讓線程等待500毫秒,如果發現還被其他線程鎖定,就返回lockiffalse
bool lockif=false

Monitor.TryEnter(object,500,ref lockif);
if(lockif)


       //
執行操作


Mutex(
互斥)互斥繼承WaitHandle(WaitHandle在異步委托的時候講過)
互斥和Monitor也很類似,也是確保只有一個進程被互斥鎖定,區別在於互斥可以跨越

多個進程(注意不是線程)來互斥同步,比如應用程序是否只能啟動一個,當然要達到這種效果必須為互斥命名,不命名的互斥不能跨進程。

Mutex mymutex = new Mutex(false,"myMutex",out mutexif);

            if (!mutexif)

            {

                //執行代碼

            }

或者******************************

            if (mymutex.WaitOne(50))

            {

                //終止線程50毫秒,直到該線程已經操作結束

                //執行代碼

            }

Semaphore(信號量),也繼承WaitHandle
信號量類似互斥鎖定Mutex,它是一種控制線程數量的互斥鎖定,首先
先定義一個信號量
var semaphore=new SemaphoreSlim(4,4);
然後遍歷20個進程,把semaphore作為參數傳到每一個進程執行的方法裡
SemaphoreSlim semaphore=o as SemaphoreSlim ;

Bool isCompleted=false;

While(!isCompleted)
{

//阻止當前進程,一直到他可以進入semaphore信號量內為止
       if(semaphore..Wait(600))
       {
              try

{

 

}finally

{

semaphore.Release();//釋放一個信號量,當然也可以指定釋放幾個信號量參數

isCompleted=true;

}

}else

{

//4個信號量已經滿了,線程繼續等待

}

}

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved