zoukankan      html  css  js  c++  java
  • C# 线程基础

    1. 线程的基本概念

    简单的讲进程就是程序分配在内存当中,等待处理器进行处理,请记住线程会消耗大量的操作系统资源。多个线程共享一个物理处理器将导致处理器忙于处理管理这些进程,而无法运行程序。

    使用线程通常是一个操作系统的任务,试图在一个单核CPU上并行执行计算任务是没有任何意义的,可能比顺序执行花费的时间更长。

    为了更好的利用现代处理器的能力,使用多线程处理程序发挥出最好的作用,这需要组织多个线程间的通讯和相互同步。

    下面将学习一下 线程的生命周期,和创建线程、挂起线程、线程等待、以及终止线程。

    创建一个线程操作

            static void Main(string[] args)
            {
                //创建一个新的线程来实现输出数字
                Thread t = new Thread(PrintNumber);
                t.Start();
                //这一行代码是在创建了一个新的线程并行执行的
                PrintNumber();
                Console.ReadLine();
            }
    
            static void PrintNumber() 
            {
                Console.WriteLine("Starting...");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(i);
                }
            }

    从上面代码可以看出一个程序始终有一个主线程在执行,而Thread是创建一个新的线程执行。两者之间是同步执行的。

    暂停线程

            static void Main(string[] args)
            {
                //创建一个带暂停的进程
                Thread t = new Thread(PrintNumberWithdelay);
                t.Start();
                //这一行就是始终执行的主线程经过(一个程序都有一个始终执行的主线程)
                PrintNumber();
            }
    
            static void PrintNumber() 
            {
                Console.WriteLine("Starting...");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(i);
                }
            }
            static void PrintNumberWithdelay() 
            {
                Console.WriteLine("暂停...");
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                    Console.WriteLine(i);
                }
            }

    很明显,主线程已经执行完毕,而新的线程在输出暂停以后还在继续执行。每次执行都会休眠2秒钟。

    线程等待

    那么如何不让主线程继续往下执行,而是等待新线程执行完毕再往下执行呢。

            static void Main(string[] args)
            {
                //创建一个带暂停的进程
                Thread t = new Thread(PrintNumberWithdelay);
                t.Start();
                t.Join();//线程等待
                Console.WriteLine("执行完毕了");
             
            }
            static void PrintNumberWithdelay()
            {
                Console.WriteLine("暂停...");
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                    Console.WriteLine(i);
                }
            }

    终止线程

            static void Main(string[] args)
            {
                //创建一个带暂停的进程
                Thread t = new Thread(PrintNumberWithdelay);
                t.Start();
                Thread.Sleep(TimeSpan.FromSeconds(3));
                t.Abort();//终止线程
                Console.WriteLine("线程终止了");         
            }

    这段代码是给线程注入了ThreadAbortException方法,导致线程被终结,这样操作是非常危险的,因为该异常可能会导致整个应用程序都崩溃。

    可以使用 ResetAbort 方法来拒绝被终止。

    检测线程状态

            static void Main(string[] args)
            {
                //创建一个带暂停的进程
                Thread t = new Thread(PrintNumberWithdelay);
                Thread t1 = new Thread(DoNothing);
                t1.Start();
                t.Start();
                for (int i = 0; i < 30; i++)
                {
                    Console.WriteLine(t.ThreadState.ToString());
                }            
                Thread.Sleep(TimeSpan.FromSeconds(3));
                t.Abort();//终止线程
                Console.WriteLine("线程终止了");
                Console.WriteLine(t.ThreadState.ToString());
                Console.WriteLine(t1.ThreadState.ToString());
            }
    
            static void PrintNumberWithdelay()
            {
                Console.WriteLine("开始啦...");
                Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                    Console.WriteLine(i);
                }
            }
            static void DoNothing()
            {
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }

    当主程序定义了两个不同的线程,一个将会被终止,而另一个则会成功运行。线程状态位于Thread 对象的ThreadState属性中。ThreadState属性是一个C#枚举对象。

    刚开始线程状态为Unstarted ,然后启动线程,并估计在一周期为30的迭代的区间中,线程状会从Running变为WitSleepJoin。

    线程优先级

        class ThreadSample
        {
            private bool _isStopped = false;
            public void Stop()
            {
                _isStopped = true;
            }
            public void CountNumbers()
            {
                long counter = 0;
                while (!_isStopped)
                {
                    counter++;
                }
                Console.WriteLine("{0} 和 {1,11}" + " count={2,13}",
                    Thread.CurrentThread.Name,
                    Thread.CurrentThread.Priority,
                    counter.ToString("NO"));
            }
        }
    
        class Program
        {
            static void RunThreads()
            {
                var sample = new ThreadSample();
                var threadOne = new Thread(sample.CountNumbers);
                threadOne.Name = "ThreadOne";
                var threadTwo = new Thread(sample.CountNumbers);
                threadTwo.Name = "ThreadTwo";
    
                threadOne.Priority = ThreadPriority.Highest;//优先级较高
                threadTwo.Priority = ThreadPriority.Lowest;//优先级较低
    
                threadOne.Start();
                threadTwo.Start();
    
                Thread.Sleep(TimeSpan.FromSeconds(2));
                sample.Stop();
    
            }
            static void Main(string[] args)
            {
                Console.WriteLine("线程状态:{0}",Thread.CurrentThread.Priority);
                Console.WriteLine("开始");
                RunThreads();           
                Thread.Sleep(TimeSpan.FromSeconds(3));
                Console.WriteLine("模拟CPU单核计算");
                //让操作系统运行在第一个CPU第一个核心上
                Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
                RunThreads();//运行时间很长
                Console.WriteLine("线程终止了");
            }
    
        }

    此程序只用于演示,通常中无需使用这种方式。

    前台线程和后台线程

        class ThreadSample
        {
            private readonly int _iterations;
            public ThreadSample(int iterations)
            {
                _iterations = iterations;
            }
            public void CountNumbers()
            {
                for (int i = 0; i < _iterations; i++)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(0.5));
                    Console.WriteLine("{0} 和 {1}",
                        Thread.CurrentThread.Name, i);
                }
    
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var samppleforegroud = new ThreadSample(10);
                var sampplebackgroup = new ThreadSample(20);
    
                var threadOne = new Thread(samppleforegroud.CountNumbers);
    
                threadOne.Name = "前台";
    
                var threadTwo = new Thread(sampplebackgroup.CountNumbers);
    
                threadTwo.Name = "后台";
                threadTwo.IsBackground = true;
    
                threadOne.Start();
                threadTwo.Start();
    
            }
    
        }

    显示创建的是前台线程, ThreadTwo是后台线程 ,通过配置第一个线程会比第二个线程先完成,前台线程如果执行完毕,那么也会把后台线程终止掉。

    向线程传递参数

    class ThreadSample
        {
    
            private readonly int _iterations;
            public ThreadSample(int iterations)
            {
                _iterations = iterations;
            }
            public void CountNumbers()
            {
                for (int i = 0; i < _iterations; i++)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(0.5));
                    Console.WriteLine("{0} 和 {1}",
                        Thread.CurrentThread.Name, i);
                }
    
            }
        }
    
        class Program
        {
            static void Count(object i)
            {
                CountNumbers((int)i);
            }
    
            static void CountNumbers(int number)
            {
                Console.WriteLine(number);
            }
    
            static void PrintNumber(int number)
            {
                Console.WriteLine(number);
            }
    
            static void Main(string[] args)
            {
                var samppleforegroud = new ThreadSample(10);
    
                var threadOne = new Thread(samppleforegroud.CountNumbers);
                threadOne.Name = "One";
                threadOne.Start();
                threadOne.Join();
                Console.WriteLine("------------");
    
    
                var threadTwo = new Thread(Count);
                threadTwo.Name = "Two";
                threadTwo.Start(8);
                threadTwo.Join();
    
                var threaThree = new Thread(() => CountNumbers(12));
                threaThree.Name = "Three";
                threaThree.Start();
                threaThree.Join();
    
                int i = 10;
                var threaFour = new Thread(() => PrintNumber(i));
                i = 20;
                var threaFour1 = new Thread(() => PrintNumber(i));
                threaFour.Start();
                threaFour1.Start();
    
            }
    
        }

    使用Lock

    abstract class CountBase
        {
            public abstract void Increment();
            public abstract void Decrement();
    
        }
    
         class Counter : CountBase
        {
            public int Count { get; private set; }
    
            public override void Increment()
            {
                Count++;
            }
    
            public override void Decrement()
            {
                Count--;
            }
        }
    
         class CounterWithLock : CountBase
        {
            private readonly object _syncroot = new object();
    
            public int Count { get; private set; }
            public override void Increment()
            {
                lock (_syncroot)
                {
                    Count++;
                }
            }
    
            public override void Decrement()
            {
                lock (_syncroot)
                {
                    Count--;
                }
            }
        }
    
        class Program
        {
            static void TestCouner(CountBase c)
            {
                for (int i = 0; i < 100000; i++)
                {
                    c.Increment();
                    c.Decrement();
                }
            }
    
            static void Main(string[] args)
            {
                var c = new Counter();
    
                var t1 = new Thread(() => TestCouner(c));
                var t2 = new Thread(() => TestCouner(c));
                var t3 = new Thread(() => TestCouner(c));
    
                t1.Start();
                t2.Start();
                t3.Start();
                t1.Join();
                t2.Join();
                t3.Join();
    
                Console.WriteLine(c.Count);
    
                var c1 = new CounterWithLock();
    
                 t1 = new Thread(() => TestCouner(c));
                 t2 = new Thread(() => TestCouner(c));
                 t3 = new Thread(() => TestCouner(c));
    
                 t1.Start();
                 t2.Start();
                 t3.Start();
                 t1.Join();
                 t2.Join();
                 t3.Join();
    
                 Console.WriteLine(c.Count);
    
    
            }
    
        }

    使用Monitor 锁定资源

    为了避免死锁,则使用Monitor 类 来避免死锁。

    Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5));

    名称:多罗贝勒
    博客地址:http://www.cnblogs.com/objctccc/
    欢迎转载

  • 相关阅读:
    hdu 2553 N皇后问题(dfs)
    hdu 1043 Eight(双向bfs)
    牛人的ACM经验 (转)
    康托和逆康托展开(转)
    hiho Mission Impossible 6(模拟 未提交验证。。)
    数组越界也可以这么巧~~~
    poj 1679 The Unique MST(次小生成树)
    zoj 3204 Connect them(最小生成树)
    hdu 4463 Outlets(最小生成树)
    廖雪峰Java1-2程序基础-8字符和字符串
  • 原文地址:https://www.cnblogs.com/objctccc/p/6150643.html
Copyright © 2011-2022 走看看