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

    线程基础

    一个进程由若干个线程组成,线程是程序执行的基本原子单位。线程是"进程"中某个单一顺序的控制流,线程是进程中的一个基本执行流,每个线程都有自己专属的寄存器(程序计数器、栈指针等),代码共享区,不同的线程可以执行同样的方法。

        多线程可以实现并行处理,可以避免某项任务长时间占用CPU时间,需要注意的是,多线程程序对于效率,应该根据任务不同的要求来选择。

    线程的命名空间System.Threading

        Thread类是线程中最重要的一个,Thread类提供了创建并控制线程,设置其优先级并获取其状态的方法。

        Thread类的声明:

    class ThreadSimple

    {

    //静态线程函数

    public static void ThreadMethodExample()

    {

    }

    }

    //调用静态方法

    Thread threadSimple = new Thread(ThreadSimple.ThreadMethodExample);

    或:

    class ThreadSimple

    {

    //静态线程函数

    public static void ThreadMethodExample()

    {

    }

    //调用静态方法

    //Thread threadSimple = new Thread(ThreadSimple.ThreadMethodExample);

    Thread threadSimple = new Thread(new ThreadStart(ThreadMethodExample));

    }

    1. 线程启动、结束

      Thread类的常用方法:

      1. IsAlive:判断线程是否处于活动状态
      2. Name:线程的名称
      3. Priority:ThreadPriority枚举类型,代表线程的优先级{Normal,AboveNormal,BelowNormal,Highest,Lowest}
      4. ThreadState:ThreadState枚举类型,代表线程的状态 { Running(线程已启动,正在执行) , StopRequested(正在请求停止此线程), SuspendRequested(正在请求挂起此线程), Background(线程正在被作为后台线程执行), Unstarted(尚未启动线程),Stopped(线程已经停止),WaitSleepJoin(线程已经被阻止),Suspended(线程已经挂起),AbortRequested(对线程调用了Thread.Abort()方法但是线程尚未收到试图终止它的挂起的System.Threading.ThreadAbortException) , Aborted(线程状态包括AbortRequested,并且该线程现在已死,但其状态尚未更改为Stopped) }
      5. Start:启动一个线程
      6. Suspend:挂起一个线程的运行(暂停、中断)
      7. Resume:继续被挂起的线程,恢复被Suspend()方法挂起的线程的执行
      8. Abort():结束一个线程的运行,终止线程
      9. Sleep():线程的休眠,使线程进入一定时间的休眠状态,时间一到,线程继续执行
    2. 线程间数据同步
      1. 线程间数据共享

        多线程编程中,如果线程间需要共享数据,需要把共享的数据设置为静态类型的,此时可以使用static关键字

      2. Lock语句同步数据访问

        线程之间的同步和通信处理,两个线程需要同时操作一个队列,一个线程进行添加操作,另一个线程进行取用元素操作。

        lock关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。Lock的语法:lock(expression)statement_block【其中expression是加锁对象,必须是引用类型,不能是数值类型,statement_block代表正在访问的共享资源的程序段】,

        lock语句可以很好地实现互斥操作,从而保护数据在某个时刻内只有一个线程可以操作该数据,直至操作完成才允许其他线程进行操作,这样就实现了按顺序操作的设计,从而避免不可预料的情况发生。

    public static void MethodSubB()

    {

    do

    {

    lock(lockExample)

    {

    i-=1;

    Console.WriteLine("线程2开始,共享数据为:i={0}",i);

    Thread.Sleep(2000); //线程A休眠2秒

    Console.WriteLine("线程2结束,共享数据值i={0}",i);

    }

    } while (true);

    }

        3.Mutex类同步数据访问
        只向某个线程授予对共享资源的独占访问权,如果一个获取了互斥体,那么想要获取该互斥体的其他线程将被挂起,直到这个线程释放该互                 斥体。

        线程可以使用Mutex.WaitOne()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都只能等待。

        4.Monitor类同步数据访问数

    Monitor类用于锁定对象,一个线程只有得到这把锁才能对该对象进行操作,对象锁保证了在可能引起混乱的情况下,一个时刻只有一个线程可以访问这个对象。

    Monitor必须和一个具体的对象相关联,但由于它是一个静态类,所以不能使用它来定义对象,而且它的所有方法都是静态的,不能使用对象来引用。

    当一个线程调用Monitor.Enter()方法锁定对象时,这个对象就归它所有了,其他线程想要访问这个对象,只有等待它调用Monitor.Exit()方法释放锁。

                Monitor类主要成员

    Enter

    在指定对象上获取排他锁

    Exit

    释放指定对象上的排它锁

    Pluse

    通知等待队列中的线程锁定对象状态的更改

    PluseAll

    通知所有的等待线程对象状态的更改

    TryEnter

    试图获取指定对象上的排他锁

    Wait

    释放对象上的锁并阻止当前线程,直到它重新获取该锁

    private static Object sObjectA = new Object();

    private static Object sObjectB = new Object();

    public static void DemoA()

    {

    if(Monitor.TryEnter(sObjectA,1000))

    {

    Thread.Sleep(1000);

    if (Monitor.TryEnter(sObjectB, 2000))

    {

    Monitor.Exit(sObjectB);

    }

    else

    {

    Console.WriteLine("TryEnter SObjectB超时...");

    }

    Monitor.Exit(sObjectA);

    }

    Console.WriteLine("执行DemoA");

    }

    public static void DemoB()

    {

    if (Monitor.TryEnter(sObjectB, 1000))

    {

    Thread.Sleep(1000);

    if (Monitor.TryEnter(sObjectA, 2000))

    {

    Monitor.Exit(sObjectA);

    }

    else

    {

    Console.WriteLine("TryEnter SObjectA超时...");

    }

    Monitor.Exit(sObjectB);

    }

    Console.WriteLine("执行DemoB");

    }

    static void Main(string[] args)

    {

    Thread threadA = new Thread(DemoA);

    Thread threadB = new Thread(DemoB);

    threadA.Start();

    threadB.Start();

    Thread.Sleep(4000);

    Console.WriteLine("线程结束");

    }

     

        5.带参数线程

        在不传递参数的情况下,可以使用ThreadStart代理来执行函数,如果要传递参数给执行函数,则可使用ParameterizedThreadStart代理来链接函数

        Thread类的4个重载的构造函数

          1.Thread(ThreadStart)[初始化Thread类的新实例]

          2.Thread(ParameterizedThreadStart)

          [初始化Thread类的新实例,指定允许对象在线程启动时传递给线程的委托]

          3.Thread(ParameterizedThreadStart,Int32)

          4.Thread(ThreadStart,Int32)

          [初始化Thread类的新实例,并指定线程的最大堆栈]

    实例:

    class ThreadDemo

    {

    public int paraA, paraB;

    public void MethodDemo()

    {

    Console.WriteLine("paraA={0},paraB={1}", paraA, paraB);

    }

    public void Print(object obj)

    {

    Console.WriteLine("传入的参数是{0}", obj.ToString());

    }

    }

    static void Main(string[] args)

    {

    ThreadDemo A = new ThreadDemo();

    A.paraA = 2;

    A.paraB = 3;

    Thread threadA = new Thread(new ThreadStart(A.MethodDemo));

    threadA.Start();

    Thread threadB = new Thread(new ParameterizedThreadStart(new ThreadDemo().Print));

    threadB.Start(" 这是传入的参数");

    Console.Write("Press any key to continue...");

    Console.ReadKey();

    }

      6.线程池ThreadPool

    线程池是可以在后台执行多个任务的线程集合,这使得主线程可以自由地异步执行其他任务。一旦池中的某个线程任务完成,它将返回到等待线程队列中等待在此被使用。线程池线程都是后台线程。

    以下情况应该使用单独的线程不宜使用线程池

    1.线程需要指定优先级

    2.线程执行的时间较长

    3.线程在单独的线程apartment中

    4.在线程执行的过程中对线程存在操作

    static void MethodA(object num)

    {

    int QueueNum = (int)num;

    Console.WriteLine("线程号:{0}", QueueNum);

    //输出空行,为了美观

    Console.WriteLine();

    }

    static void Main(string[] args)

    {

    for (int i = 0; i < 5; i++)

    {

    //在线程池中创建线程池线程来执行指定的方法(用WaitCallBack来表示),并将此线程排入线程池的队列等待执行

    ThreadPool.QueueUserWorkItem(new WaitCallback(MethodA), i);

    }

    }

  • 相关阅读:
    POJ 1795 DNA Laboratory
    CodeForces 303B Rectangle Puzzle II
    HDU 2197 本源串
    HDU 5965 扫雷
    POJ 3099 Go Go Gorelians
    CodeForces 762D Maximum path
    CodeForces 731C Socks
    HDU 1231 最大连续子序列
    HDU 5650 so easy
    大话接口隐私与安全 转载
  • 原文地址:https://www.cnblogs.com/weihanli/p/3520863.html
Copyright © 2011-2022 走看看