Multithreading With C# Cookbook---Chapter1---线程基础

概念

为防止一个应用程序控制CPU而导致其他程序或操作系统被永久挂起,操作系统采用某种方式将物理计算单元分割为一些虚拟进程,给予每个程序一点量的计算能力。且,操作系统始终能优先访问CPU,并能调整每个程序访问CPU的优先级。线程基于这一概念实现。可以认为线程是一个虚拟进程,用于独立运行一个特定的程序。

更多内容

线程会消耗大量操作系统资源。多个线程共享一个物理处理器将导致操作系统忙于管理线程,而无法运行程序。

线程生命周期:创建线程、挂起线程、线程等待以及终止线程。

需要的using

using System.Threading;
using static System.Threading.Thread;

创建线程、开启线程

 Thread t = new Thread(FunName);//传递一个方法
 t.Start();

进程

正在执行中的程序示例可被称为一个进程。进程由一个或多个线程组成。

暂停线程

让一个线程等待一段时间而不用消耗操作系统资源。

Thread.Sleep(TimeSpan.FromMilliseconds(2000));

线程等待

主程序调用了t.Join方法,该方法允许我们等待直到线程t完成,线程t完成后主程序继续允许。借助该技术可以实现两个线程间同步执行步骤:第一个线程会等待另一个线程完成后再继续执行,第一个线程等待时处于阻塞状态(与Thread.Sleep一样)。

Thread t = new Thread(PrintNumsWithDelay);
t.Start();
t.Join();
PrintNums();

终止线程

调用t.Abort方法终止线程,这个线程注入了ThreadAbortException方法,导致线程被终结。这很危险,因为该异常可以在任何时刻发生并可能彻底摧毁应用程序;且该技术也不一定总能终止线程,目标线程可以通过处理该异常并调用Thread.ResetAbort方法来拒绝被终止。因此不推荐使用Abort来终止线程,可以优先使用其他方法,比如提供一个CancellationToken方法来取消线程的执行。

Thread t = new Thread(PrintNumsWithDelay);
t.Start();
Thread.Sleep(TimeSpan.FromMilliseconds(2000));
t.Abort();

查看线程状态

刚开始线程状态为ThreadState.Unstarted,启动后ThreadState.Running,线程迭代一定次数后变为ThreadState.WaitSleepJoin,线程被终止后ThreadState.Aborted,也可能是ThreadState.AbortRequest,成功完成后变为ThreadState.Stopped

t.ThreadState

注:通过Thread.CurrentThread静态属性获取当前Thread对象。

 线程优先级

CurrentThread.Priority;//当前线程优先级
new Thread(FunName).Priority=ThreadPrioroty.Highest;//Lowest//设置程序优先级

注:限制程序单核运行

using static system.Diagnostics.Process;

{
    //codes
    GetCurrentProcess().ProcessorAffinity=new IntPtr(1);  
}

前台/后台线程

线程默认是前台线程,通过设置IsBackground属性将其设置为后台线程。注:进程会等待所有前台程序完成后再结束工作,但如果剩下的全是后台线程,则会直接结束工作。

thread.IsBackground=true;

向线程传递参数

通过Thread.Start来传递方法参数,该方法接收单个object对象。

Thread t=new Thread(FunName);
t.Start(parameter);

FunName(object parameter)
{
      //code…
}

使用C#中lock关键字

多个线程访问同一资源对象时,将会导致不确定的结果。这种情形被称为竞争条件(race condition)。竞争条件是多线程环境中非常常见的导致错误的原因。使用lock关键字来避免这种错误,如果锁定一个对象,需要访问该对象的所有其他线程则会处于阻塞状态,并等待直到该对象解除锁定,这可能导致严重的性能问题。

class Program
    {
        static void Main(string[] args)
        {
            Counter c = new Counter();
            Thread t1 = new Thread(() => TestCounter(c));
            Thread t2 = new Thread(() => TestCounter(c));
            Thread t3 = new Thread(() => TestCounter(c));
            t1.Start();
            t2.Start();
            t3.Start();
            //t1.Join();
            //t2.Join();
            //t3.Join();
            Console.WriteLine(c.Count);

            CounterWithLock c1 = new CounterWithLock();
            Thread t4 = new Thread(() => TestCounter(c1));
            Thread t5 = new Thread(() => TestCounter(c1));
            Thread t6 = new Thread(() => TestCounter(c1));
            t4.Start();
            t5.Start();
            t6.Start();
            t4.Join();
            t5.Join();
            t6.Join();
            Console.WriteLine(c1.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 _syncLock = new object();
        public int Count { get; private set; }
        public override void Decrement()
        {
            lock (_syncLock)
            {
                Count++;
            }
        }

        public override void Increment()
        {
            lock (_syncLock)
            {
                Count--;
            }
        }
    }

    abstract class CounterBase
    {
        public abstract void Increment();

        public abstract void Decrement();
    }
View Code

Monitor类锁定资源

lock关键字可能创建死锁(deadlock),使用Monitor来避免死锁。

死锁:

lock(obj1)
{
   //Code……
   lock(obj2)
   {
       //Code……
   }
}


lock(obj2)
{
    //Code……
    lock(obj1)
   {
       //Code……
   }
}
View Code

避免死锁:

lock(obj1)
{
   //Code……
   if(Monitor.TryEnter(obj2,TimeSpan.FromSeconds(5)))//避免死锁
   {
       //Code……
   }
   else
   {
      //Code……
    }
}


lock(obj2)
{
    //Code……
    lock(obj1)
   {
       //Code……
   }
}
View Code

使用Monitor类的TryEnter方法,在超时参数过期前得不到所有的lock对象,则返回false,避免死锁出现。

注:本文是在阅读《C#多线程编程实战》后所写,部分内容引用该书内容,这是一本不错的书,感谢!

原文地址:https://www.cnblogs.com/EasonDongH/p/8460946.html