C# 線程的各種知識,和使用方法


C#的各種使用方法的代碼,在學習中整理過來的。標記一下。但是線程不是越多越好,每創建一個線程都要1MB的虛擬內存,而且,線程數量超過CPU(核心)的數量的話會有線程間的上下文切換,大概30MS的樣子,這會浪費很多資源並且降低性能啊。不過C#的線程池是個不錯的選擇,但是最好不要給他設置上下限,因為這有可能會給任務帶來阻塞。

1、

#region ThreadTest One

    public class Cell
    {
        int cellContents; // Cell對象里邊的內容
        bool readerFlag = false; // 狀態標志,為true時可以讀取,為false則正在寫入
        public int ReadFromCell()
      {
        lock(this) // Lock關鍵字保證了什么,請大家看前面對lock的介紹
        {
            if (!readerFlag)//如果現在不可讀取
            { 
              try
              {
                //等待WriteToCell方法中調用Monitor.Pulse()方法
                Monitor.Wait(this);
              }
              catch (SynchronizationLockException e)
              {
                Console.WriteLine(e);
              }
              catch (ThreadInterruptedException e)
              {
                Console.WriteLine(e);
              }
            }
            Console.WriteLine("Consume: {0}",cellContents);
            readerFlag = false; //重置readerFlag標志,表示消費行為已經完成
            Monitor.Pulse(this); //通知WriteToCell()方法(該方法在另外一個線程中執行,等待中)
        }
        return cellContents;
      }
        public void WriteToCell(int n)
      {
        lock(this)
        {
            if (readerFlag)
            {
              try
              {
                Monitor.Wait(this);
              }
              catch (SynchronizationLockException e)
              {
                //當同步方法(指Monitor類除Enter之外的方法)在非同步的代碼區被調用
                Console.WriteLine(e);
              }
              catch (ThreadInterruptedException e)
              {
                //當線程在等待狀態的時候中止 
                Console.WriteLine(e);
              }
            }
            cellContents = n;
            Console.WriteLine("Produce: {0}",cellContents);
            readerFlag = true; 
            Monitor.Pulse(this);//通知另外一個線程中正在等待的ReadFromCell()方法
        }
      }
    }
    public class CellProd
    {
        Cell cell; // 被操作的Cell對象
        int quantity = 1; // 生產者生產次數,初始化為1 

        public CellProd(Cell box, int request)
        {
            //構造函數
            cell = box;
            quantity = request;
        }
        public void ThreadRun()
      {
        for(int looper=1; looper<=quantity; looper++)
            cell.WriteToCell(looper); //生產者向操作對象寫入信息
      }
    }

    public class CellCons
    {
        Cell cell;
        int quantity = 1;//消費者的消費次數

        public CellCons(Cell box, int request)
        {
            cell = box;
            quantity = request;
        }
        public void ThreadRun()
        {
            int valReturned;
            for (int looper = 1; looper <= quantity; looper++)
                valReturned = cell.ReadFromCell();//消費者從操作對象中讀取信息
        }
    }

    public class MonitorSample
    {
        public static void Main(String[] args)
        {
            int result = 0;
            //一個標志位,如果是0表示程序沒有出錯,如果是1表明有錯誤發生
            Cell cell = new Cell();

            //下面使用cell初始化CellProd和CellCons兩個類,生產和消費次數均為20次
            CellProd prod = new CellProd(cell, 20);
            CellCons cons = new CellCons(cell, 20);

            Thread producer = new Thread(new ThreadStart(prod.ThreadRun));
            Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));
            //生產者線程和消費者線程都已經被創建,但是沒有開始執行 

            try
            {
                producer.Start();
                consumer.Start();

                producer.Join();
                consumer.Join();

                Console.ReadLine();
            }
            catch (ThreadStateException e)
            {
                //當線程因為所處狀態的原因而不能執行被請求的操作
                Console.WriteLine(e);
                result = 1;
            }
            catch (ThreadInterruptedException e)
            {
                //當線程在等待狀態的時候中止
                Console.WriteLine(e);
                result = 1;
            }
            //盡管Main()函數沒有返回值,但下面這條語句可以向父進程返回執行結果
            Environment.ExitCode = result;
        }
    }

    #endregion

2、

#region ThreadTest Two
    這是用來保存信息的數據結構,將作為參數被傳遞
    public class SomeState
    {
        public int Cookie;
        public SomeState(int iCookie)
        {
          Cookie = iCookie;
        }
    }

    public class Alpha
    {
        public Hashtable HashCount;
        public ManualResetEvent eventX;
        public static int iCount = 0;
        public static int iMaxCount = 0;
        public Alpha(int MaxCount) 
        {
          HashCount = new Hashtable(MaxCount);
          iMaxCount = MaxCount;
        }

        //線程池里的線程將調用Beta()方法
        public void Beta(Object state)
        {
          //輸出當前線程的hash編碼值和Cookie的值
          Console.WriteLine(" {0} {1} :", Thread.CurrentThread.GetHashCode(),((SomeState)state).Cookie);
          Console.WriteLine("HashCount.Count=={0}, Thread.CurrentThread.GetHashCode()=={1}", HashCount.Count, Thread.CurrentThread.GetHashCode());
          lock (HashCount) 
          {
              //如果當前的Hash表中沒有當前線程的Hash值,則添加之
              if (!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode()))
                HashCount.Add (Thread.CurrentThread.GetHashCode(), 0);
              HashCount[Thread.CurrentThread.GetHashCode()] = ((int)HashCount[Thread.CurrentThread.GetHashCode()])+1;
          }

          int iX = 2000;
          Thread.Sleep(iX);
          //Interlocked.Increment()操作是一個原子操作,具體請看下面說明
          Interlocked.Increment(ref iCount);
          if (iCount == iMaxCount)
          {
              Console.WriteLine();
              Console.WriteLine("Setting eventX ");
              eventX.Set();
          }
        }
    }

    public class SimplePool
    {
        public static int Main(string[] args)
        {
          Console.WriteLine("Thread Pool Sample:");
          bool W2K = false;
          int MaxCount = 10;//允許線程池中運行最多10個線程
          //新建ManualResetEvent對象並且初始化為無信號狀態
          ManualResetEvent eventX = new ManualResetEvent(false);
          Console.WriteLine("Queuing {0} items to Thread Pool", MaxCount);
          Alpha oAlpha = new Alpha(MaxCount); //創建工作項
          //注意初始化oAlpha對象的eventX屬性
          oAlpha.eventX = eventX;
          Console.WriteLine("Queue to Thread Pool 0");
          try
          {
              //將工作項裝入線程池 
              //這里要用到Windows 2000以上版本才有的API,所以可能出現NotSupportException異常
              ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),
              new SomeState(0));
              W2K = true;
          }
          catch (NotSupportedException)
          {
              Console.WriteLine("These API's may fail when called on a non-Windows 2000 system.");
              W2K = false;
          }
          if (W2K)//如果當前系統支持ThreadPool的方法.
          {
              for (int iItem=1;iItem < MaxCount;iItem++)
              {
                //插入隊列元素
                Console.WriteLine("Queue to Thread Pool {0}", iItem);
                ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),new SomeState(iItem));
              }
              Console.WriteLine("Waiting for Thread Pool to drain");
              //等待事件的完成,即線程調用ManualResetEvent.Set()方法
              eventX.WaitOne(Timeout.Infinite,true);
              //WaitOne()方法使調用它的線程等待直到eventX.Set()方法被調用
              Console.WriteLine("Thread Pool has been drained (Event fired)");
              Console.WriteLine();
              Console.WriteLine("Load across threads");
              foreach(object o in oAlpha.HashCount.Keys)
              Console.WriteLine("{0} {1}", o, oAlpha.HashCount[o]);
          }
          Console.ReadLine();
          return 0;
        }
    }
    #endregion

3、

#region ThreadTest Three  lock互斥鎖

    public class threst
    {
        public static object LockExample = new object();
        static int i = 0;
        public static void MethodSubA()
        {
            do
            {
                lock (LockExample)
                {
                    i++;
                    Console.WriteLine("線程A開始,共享數據值i={0}", i);
                    Thread.Sleep(100);
                    Console.WriteLine("線程A結束,共享數據值i={0}", i);
                }
            } while (1 == 1);
        }
        public static void MethodSubB()
        {
            do
            {
                lock (LockExample)
                {
                    i--;
                    Console.WriteLine("線程B開始,共享數據值i={0}", i);
                    Thread.Sleep(100);
                    Console.WriteLine("線程B結束,共享數據值i={0}", i);
                }
            } while (1 == 1);
        }

        static void Main(string[] args)
        {
            Thread threadSubA = new Thread(new ThreadStart(MethodSubA));
            Thread threadSubB = new Thread(new ThreadStart(MethodSubB));

            Console.WriteLine("線程A啟動...........");
            threadSubA.Start();

            Console.WriteLine("線程B啟動...........");
            threadSubB.Start();

            do
            {
                if (Console.Read() == 'e')
                {
                    threadSubA.Abort();
                    threadSubB.Abort();
                    break;
                }
            } while (1 == 1);
        }
    }
    #endregion

4、

#region ThreadTest Four  Mutex互斥體
    class Program
    {
        public static Mutex MSample;
        public static int i = 0;
        static void Main(string[] args)
        {
            MSample = new Mutex(false);

            Thread ThreadSubA = new Thread(new ThreadStart(new SubProgram().MethodSubA));
            Thread ThreadSubB = new Thread(new ThreadStart(new SubProgram().MethodSubB));

            Console.WriteLine("線程A啟動..............");
            ThreadSubA.Start();

            Console.WriteLine("線程B啟動..............");
            ThreadSubB.Start();

            do
            {
                if (Console.Read() == 'e')
                {
                    ThreadSubA.Abort();
                    ThreadSubB.Abort();
                    break;
                }
            } while (1 == 1);
        }
    }
    class SubProgram
    {
        public void MethodSubA()
        {
            do
            {
                Program.MSample.WaitOne();
                Program.i++;
                Console.WriteLine("線程A開始,共享數據值i={0}", Program.i);
                Thread.Sleep(10);

                Console.WriteLine("線程A結束,共享數據值i={0}", Program.i);
                Program.MSample.ReleaseMutex();
                Thread.Sleep(10);
            } while (1 == 1);
        }
        public void MethodSubB()
        {
            do
            {
                Program.MSample.WaitOne();
                Program.i--;
                Console.WriteLine("線程B開始,共享數據值i={0}", Program.i);
                Thread.Sleep(10);

                Console.WriteLine("線程B結束,共享數據值i={0}", Program.i);
                Program.MSample.ReleaseMutex();
                Thread.Sleep(10);
            } while (1 == 1);
        }
    }
    #endregion

5-16、

#region ThreadTest Five
    class Program
    {
        private static object SObjectA = new object();
        private static object SObjectB = new object();

        public static void DemoA()
        {

                if (Monitor.TryEnter(SObjectA, 1000))
                {
                    try
                    {
                        Thread.Sleep(1000);
                        if (Monitor.TryEnter(SObjectB, 2000))
                            Monitor.Exit(SObjectB);
                        else
                            Console.WriteLine("TryEnter SObjectB 超時......");
                    }
                    catch { }
                    finally { Monitor.Exit(SObjectA); }
                }

            Console.WriteLine("DemoA 執行完畢..........");
        }
        public static void DemoB()
        {

                if (Monitor.TryEnter(SObjectB, 2000))
                {            
                    try
                    {
                        Thread.Sleep(2000);
                        if (Monitor.TryEnter(SObjectA, 1000))
                            Monitor.Exit(SObjectA);
                        else
                            Console.WriteLine("TryEnter SObjectB 超時......");
                    }
                    catch { }
                    finally { Monitor.Exit(SObjectB); }
                }

            Console.WriteLine("DemoB 執行完畢..........");
        }

        static void Main(string[] args)
        {
            Thread ThreadOne = new Thread(DemoA);
            Thread ThreadTwo = new Thread(DemoB);

            ThreadOne.Start();
            ThreadTwo.Start();

            Thread.Sleep(10000);
            Console.WriteLine("線程結束.....");
        }
    }
    #endregion

    #region ThreadTest Six 線程池的使用
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(MethodA),i);
            }
            Console.ReadLine();
        }
        static void MethodA(object Num)
        {
            int QueueNum = (int)Num;
            Console.WriteLine("線程號:{0}",QueueNum);
            Console.WriteLine();
        }
    }
    #endregion

    #region ThreadTest Seven 多個參數,使用結構體傳參
    public struct StructRow
    {
        public int First;
        public int Second;
    }
    class Propram
    {
        static void Main(string[] args)
        {
            ClassDemo ClassOne = new ClassDemo();
            StructRow rcM;
            rcM.First = 3;
            rcM.Second = 4;

            Thread ThreadOne = new Thread(new ParameterizedThreadStart(ClassOne.Demo));
            ThreadOne.Start(rcM);

            Console.Read();
        }
    }
    class ClassDemo
    {
        public void Demo(object rcMln)
        {
            StructRow rowCol = (StructRow)rcMln;
            for (int i = 0; i < rowCol.First; i++)
            {
                for (int j = 0; j < rowCol.Second; j++)
                {
                    Console.WriteLine("內循環輸出:{0}", j);
                }
                Console.WriteLine("外循環輸出:{0}", i);
                Console.WriteLine("\n");
            }
        }
    }
    #endregion

    #region ThreadTest Eight 創建專用線程異步執行操作
    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine("Main thread: starting a dedicated thread to do an asynchronous operation");
            Thread dedicatedThread = new Thread(ComputeBoundOp);
            dedicatedThread.Start(5);
            Console.WriteLine("Main thread: Doing other work here");
            Thread.Sleep(10000);

            dedicatedThread.Join();//等待線程終止
            Console.WriteLine("Hit <Enter> to end this program...");
            Console.ReadLine();
        }

        private static void ComputeBoundOp(object state)
        {
            Console.WriteLine("In computeBoundOp: state={0}",state);
            Thread.Sleep(1000);
        }
    }
    #endregion

    #region ThreadTest Nine  前台線程和后台線程的區別
    public static class Program
    {
        public static void Main()
        {
            Thread t = new Thread(Worker);
            t.IsBackground = true;
            t.Start();
            //如果t是一個前台進程,則應用程序10秒后才終止
            //如果t是一個后台進程,則應用程序立即終止
            Console.WriteLine("Returning from Main");
        }
        private static void Worker()
        {
            Thread.Sleep(10000);
            Console.WriteLine("Returning from Worker");
        }
    }
    #endregion

    #region ThreadTest Ten  線程池以異步方式調用一個方法
    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine("Main thread: queuing an asynchronous operation");
            ThreadPool.QueueUserWorkItem(ComputeBoundOp,5);
            Console.WriteLine("Main thread: Doing other work here");
            Thread.Sleep(10000);

            Console.WriteLine("Hit <Enter> to end this program...");
            Console.ReadLine();
        }

        private static void ComputeBoundOp(object state)
        {
            Console.WriteLine("In computeBoundOp: state={0}", state);
            Thread.Sleep(1000);
        }
    }
    #endregion

    #region ThreadTeat Eleven  如何通過阻止執行上下文的流動來影響線程邏輯調用上下文中的數據
    public class Program
    {
        public static void Main()
        {
            //將一些數據放到Main線程的邏輯調用上下文中
            CallContext.LogicalSetData("Name","Jeffrey");
            //線程池能訪問邏輯調用上下文數據
            ThreadPool.QueueUserWorkItem(state =>Console.WriteLine("Name={0}",CallContext.LogicalGetData("Name")));

            //現在阻止Main線程的執行上下文的流動
            ExecutionContext.SuppressFlow();

            //線程池線程不能訪問邏輯調用上下文數據
            ThreadPool.QueueUserWorkItem(state=>Console.WriteLine("Name={0}",CallContext.LogicalGetData("Name")));

            //恢復Main線程的執行上下文的流動
            ExecutionContext.RestoreFlow();
        }
    }
    #endregion

    #region ThreadTest Twelve CancellationTokenSource取消線程操作 .Net FrameWork 4.0
    public class Propram
    {
        public static void Main()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));//禁止被取消CancellationToken.None
            Console.WriteLine("按 <Enter> 鍵終止操作");
            Console.ReadLine();
            cts.Cancel();
            Console.ReadLine();
        }
        private static void Count(CancellationToken token, int countTo)
        {
            for (int count = 0; count < countTo; count++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Count 已經被取消");
                    token.Register(() => Console.WriteLine("Count 取消后調用了這個方法"), false);
                    break;
                }
                Console.WriteLine(count);
                Thread.Sleep(200);
            }
            Console.WriteLine("Count 執行結束");
        }
    }
    #endregion

    #region ThreadTest Thirteen  Task 取消任務
    public class Program
    {
        public static void Main()
        {
            CancellationTokenSource ctks = new CancellationTokenSource();
            Task<Int32> t = new Task<Int32>(() => sum(ctks.Token, 10000), ctks.Token);
            t.Start();
            ctks.Cancel();//t.Wait();

            try
            {
                Console.WriteLine("The sum is: " + t.Result);
            }
            catch (AggregateException x) //AggregateException 封閉異常對象的一個集合
            {
                x.Handle(e => e is OperationCanceledException);
                Console.WriteLine("Sum was canceled");
            }
            Console.ReadLine();
        }
        private static Int32 sum(CancellationToken ctk, Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; n--)
            {
                ctk.ThrowIfCancellationRequested();
                checked { sum += n; }
            }
            return sum;
        }
    }
    #endregion

    #region ThreadTest Fourteen 一個任務完成時自動啟動另一個任務
    public class Program
    {
        public static void Main()
        {
            CancellationTokenSource ctks = new CancellationTokenSource();
            Task<Int32> t = new Task<Int32>(() => sum(ctks.Token, 10000));
            t.Start();

            Task twk = t.ContinueWith(task => Console.WriteLine("The sum is: " + task.Result));//在任務 t 結束后執行任務 twk
            twk.ContinueWith(tsk=>Console.WriteLine("twk is completed with no Exception!"),TaskContinuationOptions.OnlyOnRanToCompletion);//在沒有任何異常的情況下執行這句

            Console.ReadLine();
        }
        private static Int32 sum(CancellationToken ctk, Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; n--)
            {
                checked { sum += n; }
            }
            return sum;
        }
    }
    #endregion

    #region ThreadTest Fivteen 讓任務支持父/子關系(任務可以啟動子任務)
    public static class Propram
    {
        public static void Main()
        {
            Task<Int32[]> parent = new Task<Int32[]>(() =>
            {
                var results = new Int32[3];

                new Task(() => results[0] = Sum(1000), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => results[1] = Sum(2000), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => results[2] = Sum(3000), TaskCreationOptions.AttachedToParent).Start();

                return results;
            }
            );

            parent.ContinueWith(parentTask => Array.ForEach(parent.Result, Console.WriteLine));

            parent.Start();
            Console.ReadLine();
        }
        private static Int32 Sum(Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; n--)
            {
                checked { sum += n; }
            }
            return sum;
        }
    }
    #endregion

    #region ThreadTest Sixteen 如何使用任務工廠 TaskFactory   (沒弄明白)
    public class Program
    {
        public static void Main()
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                var tf = new TaskFactory<Int32>(cts.Token, TaskCreationOptions.AttachedToParent,
                    TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                /*這個任務創建並啟動3個子任務*/
                var childTasks = new[]{
                    tf.StartNew(()=>Sum(cts.Token,1000)),
                    tf.StartNew(()=>Sum(cts.Token,2000)),
                    tf.StartNew(()=>Sum(cts.Token,Int32.MaxValue))//太大,拋出異常
                };
                
                /*任務子任務拋出異常,就取消其余子任務*/
                for (Int32 task = 0; task < childTasks.Length; task++)
                {
                    childTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);
                }

                /*所有子任務完成后,從未出錯/未取消的任務獲取返回最大值,然后將最大值傳給另一個任務來顯示結果*/
                tf.ContinueWhenAll(childTasks, completedTasks => completedTasks.Where(t => !t.Isfaulted && t.IsCanceled).Max(t => t.Result),
                    CancellationToken.None).ContinueWith(t => Console.WriteLine("最大值是:" + t.Result),
                    TaskContinuationOptions.ExecuteSynchronously);
            }
            );

            /*子任務完成后,也顯示任務未處理的異常*/
            parent.ContinueWith(p =>
            {
                /*我將所遇哦文本放到一個StringBuilder中,並值調用Console.WriteLine一次,*/
                /*因為這個任務可能和上面的任務並行執行,而我不希望任務的輸出變得不連續*/
                StringBuilder sb = new StringBuilder("The following exception(s) occurred:" + Environment.NewLine);

                foreach (var e in p.Exception.Flatten().InnerExceptions)
                    sb.AppendLine(" " + e.GetType().ToString());
                Console.WriteLine(sb.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);

            parent.Start();

            Console.ReadLine();
        }
        private static Int32 Sum(CancellationToken ctk, Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; n--)
            {
                checked { sum += n; }
            }
            return sum;
        }
    }
    #endregion

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM