• 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#多线程编程实战》后所写,部分内容引用该书内容,这是一本不错的书,感谢!

  • 相关阅读:
    技术人的思维修炼
    COMMIT在FORM中用法
    编译FORM 时出现错误 bad bind variable ’parameter.G_query_find‘
    描述性弹性域
    ORACLE EBS WebService推送报文例子 XML格式
    EBS值集,弹性域常用表
    ebs Form 表单个性化
    ebs界面颜色改变
    Oracle EBS数据定义移植工具:FNDLOAD
    在请求的参数中设置可选值列表为当前职责可访问的所有OU
  • 原文地址:https://www.cnblogs.com/EasonDongH/p/8460946.html
Copyright © 2020-2023  润新知