线程实用解析--------(三)线程的同步

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

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

下面先看一个例子:

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关键字的同步方法,但是它只能在变量一级做同步。关于后边的上边所列的同步方法不常用,所以就不再做介绍了,有兴趣的朋友可以自己去了解下。希望可以对大家有所帮助。下一节会讲一下异步操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值