c#多線程的開發

線程的創建

c#的線程的創建有兩種方式,一種是使用無參的ThreadStart,另外一種是傳參的ParameterizedThreadStart(只允許傳遞一個參數,但可以將對象作為參數傳遞,所以使用上也是非常簡單)

Demo


        static void Main(string[] args)
        {

            //MyList mylist = new MyList();
            //mylist.dict();
            SaleData sale = new SaleData(100);
            checkproduce checkproduce = new checkproduce();
            //註冊檢查函數
            sale.checkData += new SaleData.checkNum(checkproduce.check);
            ThreadStart threadStart = new ThreadStart(sale.saleDone);
            Thread thread = new Thread(threadStart);
            thread.Start();
            Console.WriteLine("業務執行完畢");

            
            //此處需要傳遞一個靜態函數
            Thread t = new Thread(new ParameterizedThreadStart(Add));
            //將對象直接傳遞過去
            t.Start(sale);
            Console.ReadKey();
        }
        static void Add(object data)
        {
        
        }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static myjob.EventTest;

namespace myjob
{
    //訂閱器
    public class checkproduce { 
        
        //檢查庫存值
        public void check()
        {
            Console.WriteLine("觸發庫存檢查函數,庫存減少 ");
            Thread.Sleep(1000);

            Console.WriteLine("庫存檢查完畢");            
        }
    }
    //銷售數據校對
    public class SaleData {
       public int sale_num=10;
       public delegate void   checkNum();
       public event checkNum checkData;
       
        public SaleData(int num)
        {
            sale_num = num;
        }
       
        public void saleDone()
        {
            Console.WriteLine("啟動新的子線程");
            checkData();
        }

        public static void saleNum(SaleData saleData)
        {

            Console.WriteLine("銷售" + saleData.sale_num);
            
        }







    }

}

線程的喚醒與阻塞

c#中把線程的狀態分為終止狀態(運行),非終止狀態(被阻塞)兩種狀態。為了更好地管理現成的狀態,使用兩個工具類AutoResetEvent和ManualResetEvent進行管理。

AutoResetEvent

autoresetevent設置為false,waitone需要等待信號,為true時候不會阻塞

 public  class ThreadDemo
    {   
        public static AutoResetEvent threadPayMoneyOne = new AutoResetEvent(false);
        public void wake()
        {
            Console.WriteLine("線程啟動");
            threadPayMoneyOne.WaitOne();
            Thread.Sleep(3000);
            Console.WriteLine("執行完畢");
        }
   static void Main(string[] args) {
            ThreadDemo threadDemos = new ThreadDemo();
            Thread thread = new Thread(new ThreadStart(threadDemos.wake));       
            thread.Start();
            //喚醒子線程
            //ThreadDemo.threadPayMoneyOne.Set();
            Console.WriteLine("繼續執行業務");
            Console.ReadKey();
        }
c#多線程的開發_第1张图片

ManualResetEvent

ManualResetEvent 调用一次Set()后将允许恢复所有被阻塞线程。需手动在调用WaitOne()之后调用 Reset()重置信号量状态为非终止,然后再次调用WaitOne()的时候才能继续阻塞线程,反之则不阻塞

 public class ThreadDemo2
    {   // 
        public static ManualResetEvent threadtwo = new ManualResetEvent(false);
        public static void wake()
        {
            Console.WriteLine("線程啟動");
            threadtwo.WaitOne();
            Thread.Sleep(3000);
            Console.WriteLine("執行完畢");
            Console.WriteLine("————————————");
        }
    }
c#多線程的開發_第2张图片

兩者的區別

1.ManualResetEvent 调用一次Set()后将允许恢复所有被阻塞线程。需手动在调用WaitOne()之后调用Reset()重置信号量状态为非终止,然后再次调用WaitOne()的时候才能继续阻塞线程,反之则不阻塞

2.AutoResetEvent,调用一次Set()只能继续被阻塞的一个线程,多次调用Set()才行,但不需手动调用Reset();再次调用WaitOne()的时候又能阻塞线程,也是和前者的区别

3.两者单个实例均可阻塞一个或多个线程,在多个线程中调用 主线程 创建的 两者单个实例.WaitOne(),前提是两者实例必须是非终止状态

4.两者实例化构造参数解释

true:设置终止状态。相当于调用了Set(),即首次不会被WaitOne()阻塞,下次执行WaitOne()才会被阻 塞

false:设置非终止状态。遇到WaitOne()立即阻塞所在的一个或多个线程

5.两者都只会阻塞WaitOne()所在的线程,WaitOne()可被多个线程调用

優秀的Task異步管理類

為了更好地進行異步任務的管理,c#使用Task類,可以非常輕鬆實現任務的編排,定時停止等需求。

c#多線程的開發_第3张图片

創建Task

task的創建有三種方式,一種是使用action傳遞參數,一種使用lmada表達式創建,和最後的 Task.Factory.。task任務需要使用start方法啟動,wait方法設置任務的啟動。

 static void Main(string[] args)
        {
           
            Action gettask = (object obj) => {
                CallBack callBack = new CallBack();
                callBack.download();
             };
            //此處需要傳遞參數,第二值個不能為null
            Task t1 = new Task(gettask,"download");
            t1.Start();
            //調度返回
            t1.Wait();
           
            Task task2 = Task.Run(() =>
            {
                CallBack callBack = new CallBack();
                callBack.download();
            });
            task2.Wait();
            Task task3 = Task.Factory.StartNew(() =>
            {
                CallBack callBack = new CallBack();
                callBack.download();
            });
            task3.Wait();
            Task t4 = new Task(gettask,"download");
            t4.RunSynchronously();
        }
   public class CallBack
    {
        public int  download()
        {
            Console.WriteLine("開始下載");
            Thread.Sleep(1000);
            Console.WriteLine("下載完畢");
            return 0;
        }
    } 
   

任務超時處理

處理超時任務,只需要在wait添加超時參數,一旦超時,直接關閉後台任務

      static void Main(string[] args)
        {

            Task task2 = Task.Run(() =>
            {
                CallBack callBack = new CallBack();
                callBack.download();
            });
            //設置超時直接停止任務
            task2.Wait(1000);
            Console.WriteLine("任務運行狀態為 {0}", task2.Status);

        }

多任務編排

設置指定的任務執行是由上一個任務結束

            //task2停止才能開始執行task1
            Task task2 = Task.Run(() =>
            {
                CallBack callBack = new CallBack();
                callBack.download();
            });
            //設置超時直接停止任務
            task2.Wait(500);
            
            
            while (true)
            {
                Console.WriteLine("任務運行狀態為 {0}", task2.Status);
                if (task2.IsCompleted == true)
                {
                    Task task1 = Task.Run(() =>
                    {
                        CallBack callBack = new CallBack();
                        callBack.download();
                        Console.WriteLine("任務一停止");
                    });
                    task1.Wait();
                    break;
                }

             
            }

等待所有任務全部完成才開始執行任務

當不需要指定等待的任務時候,可以選擇使用waitany和waitall語法,這兩者的區別在於waitany只等待一個任務,而waitall是等待任務組全部執行完成。

            //多任務編排  不會阻塞主線程
            Task[] tasks = new Task[10];
         
            for (int i = 0; i < 10; i++)
            {
                tasks[i] = Task.Run(() => {
                    Thread.Sleep(200);
                    Console.WriteLine("任務池任務結束");
                });
            }
            Task.WaitAll(tasks);
            foreach (var t in tasks)
                Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
            Console.WriteLine("任務池結束");

你可能感兴趣的:(C#,c#)