欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c#多線程之線程基礎

 更新時間:2022年04月18日 15:07:57   作者:農(nóng)碼一生  
本文詳細講解了c#多線程之線程基礎,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、簡介

1.為了防止一個應用程序控制CPU而導致其他應用程序和操作系統(tǒng)本身永遠被掛起這一可能情況,操作系統(tǒng)不得不使用某種方式將物理計算分割為一些虛擬的進程,并給予每個執(zhí)行程序一定量的計算能力。此外操作系統(tǒng)必須始終能夠優(yōu)先訪問CPU,并能調整不同程序訪問CPU的優(yōu)先級。線程正式這一慨念的實現(xiàn)。

2.多線程優(yōu)缺點:
多線程優(yōu)點:可以同時執(zhí)行多個計算任務,有可能提高計算機的處理能力,使得計算機每秒能執(zhí)行越來越多的命令
多線程缺點:消耗大量的操作系統(tǒng)資源。多個線程共享一個處理器將導致操作系統(tǒng)忙于管理這些線程,而無法運行程序。

二、創(chuàng)建線程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(PrintNumbers));//無參數(shù)的委托,把方法的引用當做參數(shù)
            t1.Start();

            Thread t2 = new Thread(new ParameterizedThreadStart(PrintNumbers));//有參數(shù)的委托,把方法的引用當做參數(shù)
            t2.Start(10);
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
            }
        }

        //注意:要使用ParameterizedThreadStart,定義的參數(shù)必須為object
        static void PrintNumbers(object count)
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < Convert.ToInt32(count); i++)
            {
                Console.WriteLine(i);
            }
        }
    }
}

注釋:

1.我們只需指定在不同線程運行的方法名,而C#編譯器會在后臺創(chuàng)建這些對象。

2.要使用ParameterizedThreadStart,定義的參數(shù)必須為object類型。

三、暫停線程

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(PrintNumbersWithDelay);
            t1.Start();
            PrintNumbers();
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting: " + i);
            }
        }

        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                //var a = TimeSpan.FromSeconds(2);
                Thread.Sleep(TimeSpan.FromSeconds(2));//暫停兩秒
                Console.WriteLine("In 2.Starting: " + i);
            }
        }
    }

注釋:使用Thread.Sleep(TimeSpan.FromSeconds(2));暫停線程一段時間

四、線程等待

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting...");
            Thread t = new Thread(PrintNumbersWithDelay);
            t.Start();
            t.Join();   //使用Join等待t完成后,再向下執(zhí)行PrintNumbers,如果注釋掉輸出明顯不同
            PrintNumbers();
            Console.WriteLine("Thread Complete");
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting:" + i);
            }
        }

        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 2.Starting:" + i);
            }
        }
    }

注釋:使用t.Join();   等待t完成。

五、終止線程

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Program...");
            Thread t1 = new Thread(PrintNumbersWithDelay);
            t1.Start();
            Thread.Sleep(TimeSpan.FromSeconds(7));//此時t1線程會執(zhí)行7秒
            t1.Abort();    //使用Abort()終止線程
            Console.WriteLine("Thread t1 has been aborted");
            Thread t2 = new Thread(PrintNumbers);
            t2.Start();
            Console.ReadLine();
        }

        static void PrintNumbers()
        {
            Console.WriteLine("1.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("In 1.Starting:" + i);
            }
        }
        static void PrintNumbersWithDelay()
        {
            Console.WriteLine("2.Starting...");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 2.Starting:" + i);
            }
        }
    }

注釋:使用Thread實例的Abort方法終止線程。

六、檢測線程狀態(tài)

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Start Program...");
            Thread t1 = new Thread(PrintNumbersWithStatus);
            Thread t2 = new Thread(DoNothing);
            Console.WriteLine("t1 status:" + t1.ThreadState.ToString());//獲取實例線程狀態(tài)
            t2.Start();
            t1.Start();
            for (int i = 0; i < 30; i++)
            {
                Console.WriteLine("t1 status:" + t1.ThreadState.ToString() + "\t" + "t2 status:" + t2.ThreadState.ToString());
            }
            Thread.Sleep(TimeSpan.FromSeconds(7));
            t1.Abort();
            Console.WriteLine("thread t1 has been aborted");
            Console.WriteLine("t1 status:" + t1.ThreadState.ToString());
            Console.WriteLine("t2 status:" + t2.ThreadState.ToString());
            Console.ReadLine();
        }

        private static void PrintNumbersWithStatus()
        {
            Console.WriteLine("1.Starting...");
            Console.WriteLine("In 1.Starting t1 status:" + Thread.CurrentThread.ThreadState.ToString());//獲取當前線程狀態(tài)
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
                Console.WriteLine("In 1.Starting:" + i);
            }
        }

        private static void DoNothing()
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine("t2 Console...");
        }
    }

注釋:使用Thread.ThreadState獲取線程的運行狀態(tài)。ThreadState是一個C#枚舉。謹記:不要在程序中使用線程終止,否則可能會出現(xiàn)意想不到的結果

七、線程優(yōu)先級

class Program
    {
        static void Main(string[] args)
        {
            //讓操作系統(tǒng)的所有線程運行在多個CPU核心上
            Console.WriteLine($"Current thread priority: {Thread.CurrentThread.Priority}");
            Console.WriteLine("Running on all cores available");//獲取實例線程狀態(tài)
            RunThreads();

            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine("Running on a single Core");
            //讓操作系統(tǒng)的所有線程運行在單個CPU核心上
            Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
            RunThreads();
            Console.ReadLine();
        }

        private static void RunThreads()
        {
            var sample = new ThreadSample();
            var t1 = new Thread(sample.CountNumbers);
            t1.Name = "Thread One";
            var t2 = new Thread(sample.CountNumbers);
            t2.Name = "Thread Two";

            t1.Priority = ThreadPriority.Highest;//使用Priority設置線程的優(yōu)先級
            t2.Priority = ThreadPriority.Lowest;
            t1.Start();
            t2.Start();//此處t2優(yōu)先級低于t1,t2等待t1釋放資源。

            Thread.Sleep(TimeSpan.FromSeconds(2));
            sample.Stop();
        }
    }

    class ThreadSample
    {
        private bool _isStopped = false;
        public void Stop()
        {
            _isStopped = true;
        }
        public void CountNumbers()
        {
            long counter = 0;
            while (!_isStopped)
            {
                counter++;
            }
            Console.WriteLine($"{Thread.CurrentThread.Name} with {Thread.CurrentThread.Priority} priority has a count={counter.ToString("N0")}");
        }
    }

注釋:單核執(zhí)行多線程耗費的時間比多核的多很多。

八、前臺線程和后臺線程

class Program
    {
        static void Main(string[] args)
        {
            var sampleForground = new ThreadSample(10);
            var sampleBackground = new ThreadSample(20);
            var t1 = new Thread(sampleForground.CountNumbers);//方法的引用
            t1.Name = "ForegroundThread"; //沒有明確聲明的均為前臺線程

            var t2 = new Thread(sampleBackground.CountNumbers);
            t2.Name = "BackgroundThread";
            t2.IsBackground = true;   //設置為后臺線程

            t1.Start();
            t2.Start();
            Console.ReadLine();

        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 0; i < _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

注釋:進程會等待所有的前臺線程完成后再結束工作,但是如果只剩下后臺線程,則會直接結束工作。

九、向線程傳遞參數(shù)

class Program
    {
        static void Main(string[] args)
        {
            ThreadSample sample = new ThreadSample(5);
            Thread t1 = new Thread(sample.CountNumbers);
            t1.Name = "ThreadOne";
            t1.Start();
            t1.Join();
            Console.WriteLine("--------------------------");

            Thread t2 = new Thread(Count);
            t2.Name = "ThreadTwo";
            t2.Start(3);
            t2.Join();
            Console.WriteLine("--------------------------");

            //使用lambda表達式引用另一個C#對方的方式被稱為閉包。當在lambda表達式中使用任何局部變量時,C#會生成一個類,并將該變量作為該類的一個屬性,但是我們無須定義該類,C#編譯器會自動幫我們實現(xiàn)
            Thread t3 = new Thread(() => CountNumbers(5));
            t3.Name = "ThreadThree";
            t3.Start();
            t3.Join();
            Console.WriteLine("--------------------------");

            int i = 10;
            Thread t4 = new Thread(() => PrintNumber(i));

            i = 20;
            Thread t5 = new Thread(() => PrintNumber(i));
            t4.Start();
            t5.Start();
            //t4, t5都會輸出20, 因為t4,t5沒有Start之前i已經(jīng)變成20了
            Console.ReadKey();
        }

        static void Count(object iterations)
        {
            CountNumbers((int)iterations);
        }

        static void CountNumbers(int iterations)
        {
            for (int i = 1; i <= iterations; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }

        static void PrintNumber(int number)
        {
            Console.WriteLine(number);
        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 1; i <= _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

十、使用C# Lock 關鍵字

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Incorrect Counter");
            Counter c1 = new Counter();
            var t1 = new Thread(() => TestCounter(c1));
            var t2 = new Thread(() => TestCounter(c1));
            var t3 = new Thread(() => TestCounter(c1));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();
            Console.WriteLine($"Total Count: {c1.Count}");
            Console.WriteLine("------------------------");

            //使用LOCK關鍵字,Count同一時刻只允許一個線程訪問
            Console.WriteLine("Correct counter");
            CounterWithLock c2 = new CounterWithLock();
            t1 = new Thread(() => TestCounter(c2));
            t2 = new Thread(() => TestCounter(c2));
            t3 = new Thread(() => TestCounter(c2));
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();
            Console.WriteLine($"Total count:{c2.Count}");
            Console.ReadLine();
        }

        static void TestCounter(CounterBase c)
        {
            for (int i = 0; i < 100000; i++)
            {
                c.Increment();
                c.Decrement();
            }
        }

        //子類
        class Counter : CounterBase
        {
            public int Count { get; private set; }
            //重寫基類方法
            public override void Decrement()
            {
                Count--;
            }

            public override void Increment()
            {
                Count++;
            }
        }

        //子類
        class CounterWithLock : CounterBase
        {
            private readonly object _asyncRoot = new object();
            public int Count { get; private set; }
            //重寫基類方法
            public override void Decrement()
            {
                lock (_asyncRoot)
                {
                    Count--;
                }
            }

            public override void Increment()
            {
                lock (_asyncRoot)
                {
                    Count++;
                }
            }
        }

        //基類
        abstract class CounterBase
        {
            public abstract void Increment();

            public abstract void Decrement();
        }
    }
    class ThreadSample
    {
        private readonly int _iteration;

        public ThreadSample(int iteration)//構造函數(shù)
        {
            _iteration = iteration;
        }

        public void CountNumbers()
        {
            for (int i = 1; i <= _iteration; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
            }
        }
    }

注釋:不加鎖,得出的結果不確定,競爭條件下很容易出錯。加鎖得出的結果是正確的,但是性能受到了影響

十一、使用Monitor類鎖定資源

class Program
    {
        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();
            new Thread(() => LockTooMuch(lock1, lock2)).Start();
            lock (lock2)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");
               
                //直接使用Monitor.TryEnter, 如果在第二個參數(shù)之前還未獲取到lock保護的資源會返回false
                if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
                {
                    Console.WriteLine("Acquired a protected resource successfully");
                }
                else
                {
                    Console.WriteLine("Timeout acquiring a resource");
                }
            }
            new Thread(() => LockTooMuch(lock1, lock2)).Start();
            Console.WriteLine("-----------------------------");
         
            /* 下面代碼會造成死鎖, 所以注釋掉
            lock (lock2)
            {
                Console.WriteLine("This will be a deadlock!");
                Thread.Sleep(1000);
                lock (lock1)
                {
                    Console.WriteLine("Acquired a protected resource successfully");
                }
            }
            */
        }

        static void LockTooMuch(object lock1, object lock2)
        {
            lock (lock1)
            {
                Thread.Sleep(1000);
                lock (lock2);
            }
        }
    }

注釋:Monitor.TryEnter在指定的時間內嘗試獲取指定對象上的排他鎖

十二、處理異常

class Program
    {
        static void Main(string[] args)
        {
            Thread t = new Thread(FaultyThread);
            t.Start();
            t.Join();
            try
            {
                t = new Thread(BadFaultyThread);
                t.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("We won't get here");
            }
        }
        static void BadFaultyThread()
        {
            Console.WriteLine("Starting a bad faulty thread.....");
            Thread.Sleep(TimeSpan.FromSeconds(2));
            //這個異常主線程無法捕捉到,因為是在子線程拋出的異常。需要在子線程中加入try...catch捕獲異常
            throw new Exception("Boom!");
        }
        static void FaultyThread()
        {
            try
            {
                Console.WriteLine("Starting a faulty thread...");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                throw new Exception("Boom!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception handled: {ex.Message}");
            }
        }
    }

到此這篇關于c#多線程之線程基礎的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 如何使用VS中的快捷鍵快速格式化代碼使好看,整齊

    如何使用VS中的快捷鍵快速格式化代碼使好看,整齊

    這篇文章主要介紹了如何使用VS中的快捷鍵快速格式化代碼使好看,整齊,非常不錯具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Unity 百度AI實現(xiàn)人像動漫化效果

    Unity 百度AI實現(xiàn)人像動漫化效果

    這篇文章主要介紹了Unity如何接入百度AI接口, 運用對抗生成網(wǎng)絡技術,為用戶量身定制千人千面的二次元動漫形象,并支持通過參數(shù)設置,生成二次元動漫人像。感興趣的可以學習一下
    2022-01-01
  • C# 任務的異常和延續(xù)處理

    C# 任務的異常和延續(xù)處理

    本文主要介紹了C# 任務的異常和延續(xù)處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-12-12
  • Unity2D實現(xiàn)游戲回旋鏢

    Unity2D實現(xiàn)游戲回旋鏢

    這篇文章主要為大家詳細介紹了Unity2D實現(xiàn)游戲回旋鏢,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C#中的委托使用

    C#中的委托使用

    委托是C#中新加入的一個類型,可以把它想作一個和Class類似的一種類型,和使用類相似,使用一個委托時,需要兩個步驟,首先你要定義一個委托,就像是定義一個類一樣;然后,你可以創(chuàng)建一個或多個該委托的實例。
    2016-07-07
  • 基于c# 類、接口、結構的聯(lián)系與區(qū)別詳解

    基于c# 類、接口、結構的聯(lián)系與區(qū)別詳解

    本篇文章是對c#中類與接口以及結構的聯(lián)系與區(qū)別進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • c# 插入數(shù)據(jù)效率測試(mongodb)

    c# 插入數(shù)據(jù)效率測試(mongodb)

    這篇文章主要介紹了c# 插入數(shù)據(jù)效率測試(mongodb),插入的速度要比Mysql和sqlserver都要快需要的朋友可以參考下
    2018-03-03
  • winform 中顯示異步下載的圖片

    winform 中顯示異步下載的圖片

    本文主要介紹利用WebClient異步下載圖片,顯示在GridView上,需要的朋友可以參考下。
    2016-05-05
  • C#索引器簡單實例代碼

    C#索引器簡單實例代碼

    打開.Net Framework源代碼隨便看幾個類,就會發(fā)現(xiàn)索引器的影子。索引器可以被重載,可以接收一個或者多個參數(shù),但是不可以定義為靜態(tài)的??梢杂藐P聯(lián)數(shù)組的方式訪問索引器。
    2013-03-03
  • C#實現(xiàn)將DataTable內容輸出到Excel表格的方法

    C#實現(xiàn)將DataTable內容輸出到Excel表格的方法

    這篇文章主要介紹了C#實現(xiàn)將DataTable內容輸出到Excel表格的方法,較為詳細的分析了C#基于DataTable保存Excel數(shù)據(jù)的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08

最新評論