zoukankan      html  css  js  c++  java
  • 线程实用解析(三)线程的同步

         上一节主要讲了创建调用有参(多参)函数的线程和线程池的一些内容,这一节主要讲线程的同步。

         多线程的出现解决了吞吐量和响应速度的问题,但同时也带来了资源共享问题,如死锁和资源争用。为单个资源分配多个线程可能会导致同步问题。何为线程同步呢?所谓同步,是指多个线程之间存在先后执行顺序的关联关系。如果一个线程必须在另一个线程完成某个工作后才能继续执行,则必须考虑如何让其他保持同步,以确保在系统上同时运行多个线程而不会出现死锁或逻辑错误。

    下面先看一个例子:

     

    class Program

        {

            static void Main(string[] args)

            {

                Thread thread = new Thread(new ThreadStart(TestShow));

                Thread thread1 = new Thread(new ThreadStart(TestShow1));

                thread.Start();

                thread1.Start();

                Console.ReadKey();

            }

            static bool biaoJi = false;

            static void TestShow()

            {

                if (!biaoJi)

                {

                    biaoJi = true;

                    Console.WriteLine("标记为False");               

                }

            }

            static void TestShow1()

            {

                if (biaoJi)

                {  Console.WriteLine("标记为True");}

            }

    这个程序很简单,就是创建两个线程,分别调用两个函数输出一句话,两个函数都共用到了一个全局变量biaoJi,在TestShow()里边将biaoJi的值改为False,运行之后的结果如下:

     

    或者

    出现第一种结果原因,我们在TestShow里将biaoJi值改为true,在TestShow1里执行ifbiaoJi)时为biaoJi值为true,所以可以输出两句话。

    出现第二句话的原因在于,两个线程同时访问biaoJi值,此时biaoJi值为发生变化,仍未false,故在执行TestShow1biaoJi值仍为false,所以只能输出一句话

    这里就出现了线程的同步问题,结果一是我们想要的结果,但是在程序的运行过程中,往往会出现像结果二那样的结果。

    如果解决这样的问题呢?为了解决这些问题,System.Threading命名空间提供了多个用于同步线程的类。这些类包括Mutex,Monitor,Interlocked,AutoResetEvent. 下面会逐步介绍一些解决同步的方法。

    一、最简单也是最常用的方法,C#提供的Lock方法

    Lock关键字能确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码段,则它将一直等待,直到锁定的对象被释放以后才能进入临界区。

    下面演示下如何使用Lock

    代码如下:

         Private static readonly object obj=new object();

    static void TestShow()

            {

               Lock(obj)

              {

                if (!biaoJi)

                {

                    biaoJi = true;

                    Console.WriteLine("标记为False");    

                }

          }

            }

    这样不管怎么调用显示的结果永远都是上例所示的第一种结果。

    Lock使用方法:

     Lock键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。 此语句的形式如下:

    Object obj = new Object();lock (obj){    // code section.}

    Lock注意事项:

    最佳做法是定义 private 对象来锁定或 private static 对象变量来保护所有实例所共有的数据,锁定的对象不能为空

    二、Monitor

    Lock语句经过编译器解析为Monitor类。Monitor类的效果和Lock基本是一样的。

    可以通过以下方式实现同步:

    Lock方式: lockobj)

         {

           //code section

                }

    Monitor类(为静态类):   Monitor.Enter(obj);

                             //code section

                             //........

                             Monitor.Exit(obj);

    示例:

         static void TestShow()

            {

                Monitor.Enter(obj);

                    if (!biaoJi)

                    {

                        biaoJi = true;

                        Console.WriteLine("标记为False");

                    }

                    Monitor.Exit(obj);

            }

    除此之外Monitor还有一个优点就是可以设置一个等待获得锁定的超时值,用以避免无限期的锁定。通过Monitor.TryEnter(object objTimespan time)来设置等待获得锁定的最长时间

    使用示例:

    ifMonitor.TryEnter(obj,1000){try  { ........... }finally { //当时间超过1秒的时候,线程不再等待 Monitor.Exit(obj); }实例:

    static void TestShow()

            {

                if (Monitor.TryEnter(obj, 2000))

                {

                    try

                    {

                        if (!biaoJi)

                        {

                            Thread.Sleep(3000);

                            biaoJi = true;

                            Console.WriteLine("标记为False");

                        }

                    }

                    catch { Monitor.Exit(obj); }  }

            }

    这样因为线程在修改biaoJi值时,休眠的3秒,超出了Monitor设置的等待时间,所以另一个线程已经开始执行了,执行时在函数TestShow1()中,biaoJi的值仍为false所以只输出了一句话。等到2个线程都执行完毕时,此时biaoJi的值为True

    三、Mutex

    Mutex的功能和C# 中的Lock一样,不同的是它可以跨进程在操作系统中,许多线程常常需要共享资源,而这些资源往往要求一次只能为一个线程服务,这种排他性地使用共享资源称为线程间的互斥。线程互斥实质上也是同步,可以看做一种特殊的线程同步。但是,进入和释放一个Mutex要花费几毫秒,效率会比较低

    通常我们会使用一个Mutex的实例,调用WaitOne方法来获取锁,ReleaseMutex方法来释放锁

    方法如下:

    Mutex m = new Mutex();

      m.WaitOne();

    //code section

    //...

    m.ReleaseMutex();

    此外我们还可以为WaitOne()函数设置参数,以防止无限期的等待。

    Mutex类还有一些其他的方法:比如:

    MutexWaitAll()函数//等待所有的线程操作

    MutexWaitAny()函数//多个操作时,等待指定的某个线程操作

    但是在操作结束后,一定要分别进行释放。

     

    今天到这里基本上就这些了,当然这些都是比较常用的解决线程同步的方法,还有其他的一些方法比如AutoResetEvent ManualResetEvent  EventWaitHandle ,还有一个volatile关键字的同步方法,但是它只能在变量一级做同步。关于后边的上边所列的同步方法不常用,所以就不再做介绍了,有兴趣的朋友可以自己去了解下。希望可以对大家有所帮助。下一节会讲一下异步操作。

  • 相关阅读:
    OPENC函数 UF_CSYS UF_MTX UF_VEC (判断矢量平行)(UF_VEC3_is_parallel)
    OPENC函数 UF_CUTTER UF_NCGROUP UF_PARAM(如何创建刀具)(UF_CUTTER_create)
    OPENC函数 (UF_setup UF_ncgroup UF_oper)(创建程序组并创建程序,然后把程序放入组中)(UF_OPER_create)
    OPENC函数 UF_CAM UF_NCGROUP (UF_CAM_opt_ask_types UF_CAM_opt_ask_subtypes UF_NCPROG_create UF_NCGROUP_accept_member)
    OPENC函数UF_UI_ONT UF_OPER (过切检查) (UF_OPER_is_path_gouged)
    OPENC函数 UF_SETUP UF_NCGROUP(获取CAM模块中 程序 机床 几何 加工方法的所有名称)(UF_SETUP_ask_geom_root UF_SETUP_ask_program_root)
    OPENC函数 UF_UI_ONT UF_OPER函数(对当前程序进行操作(获取名称))(UF_UI_ONT_ask_selected_nodes、UF_OPER_ask_cutter_group等)
    OPENC函数 UF_TRNS(平移 变换)( uf5943 , uf5947)
    openstackM版本安装
    openstack及组件简要介绍
  • 原文地址:https://www.cnblogs.com/Olive116/p/2712219.html
Copyright © 2011-2022 走看看