通过实例学C#之Mutex(互斥锁)类

作用

        当线程A需要对数据1进行判断,然后根据判断结果进行后续操作时,如果线程B,此刻也对数据1进行操作,可能会产生意向不到的错误。

        例如,设备J对工件X的温度进行判断,得知工件的温度满足条件后,可以进行下一个工艺操作,此时,如果另一个设备K对工件X进行降温操作,那么,工件X的温度就不满足执行后续制作工艺条件,这时候,如果强行进行后续操作,可能会产生次品。

        那么,中间出现问题的步骤是在哪里呢?很明显,当设备J对工件X进行温度判断后,直到后面工艺执行完,按理说都不能让其他设备对工件X进行温度上的控制。而互斥锁,就可以把工件X锁住,此时,所有其他设备都无法改变其温度,等执行完后续工艺后,再解锁,然后其他设备就可以对工件X的温度进行控制了。


构造函数

Mutex()

        创建一个Mutex互斥锁对象,且当前线程对互斥锁无所有权,如果需要获取对互斥锁的所有权,需要使用WaitOne()方法。

不使用互斥锁实例:

static int count = 0;        //用于计数

static void Main(string[] args)
{
    Thread t1 = new Thread(ShowValue);
    Thread t2= new Thread(ChangeValue);

    t1.Start();     //线程1启动
    t2.Start();     //线程2启动

    Console.WriteLine("主线程结束,请按任意键退出");
    Console.ReadKey();
}

//线程1方法
static void ShowValue()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("t1:count值为:" + count.ToString());
        Thread.Sleep(1000);
    }
}

//线程2方法
static void ChangeValue()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("-------t2--------对count进行+1操作");
        count++;
        Console.WriteLine("-------t2--------count值为:" + count.ToString());
        Thread.Sleep(1000);
    }
}

运行结果:

主线程结束,请按任意键退出
t1:count值为:0
-------t2--------对count进行+1操作
-------t2--------count值为:1
-------t2--------对count进行+1操作
-------t2--------count值为:2
t1:count值为:1
t1:count值为:2
-------t2--------对count进行+1操作
-------t2--------count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:4
t1:count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:5
t1:count值为:4

可以看到,子线程的操作对主线程的读数有影响。


如果希望主线程执行过程中,count保持不变,就需要使用互斥锁Mutex对象。实例如下:

static int count = 0;        //用于计数
static Mutex mutex = new Mutex();      //创建互斥锁实例
static void Main(string[] args)
{
    Thread t1 = new Thread(ShowValue);
    Thread t2= new Thread(ChangeValue);
    
    t1.Start();     //线程1启动
    t2.Start();     //线程2启动

    Console.WriteLine("主线程结束,请按任意键退出");
    Console.ReadKey();
}

//线程1方法
static void ShowValue()
{
    mutex.WaitOne();        //如果互斥锁的所有权被释放,那么线程1获取互斥锁的所有权
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("t1:count值为:" + count.ToString());
        Thread.Sleep(1000);
    }
    mutex.ReleaseMutex();        //线程1释放互斥锁
}

//线程2方法
 static void ChangeValue()
 {
     mutex.WaitOne();        //如果互斥锁的所有权被释放,那么线程2获取互斥锁的所有权
     for (int i = 0; i < 5; i++)
     {
         Console.WriteLine("-------t2--------对count进行+1操作");
         count++;
         Console.WriteLine("-------t2--------count值为:" + count.ToString());
         Thread.Sleep(1000);
     }
     mutex.ReleaseMutex();        //线程2释放互斥锁
 }

运行结果:

主线程结束,请按任意键退出
t1:count值为:0
t1:count值为:0
t1:count值为:0
t1:count值为:0
t1:count值为:0
-------t2--------对count进行+1操作
-------t2--------count值为:1
-------t2--------对count进行+1操作
-------t2--------count值为:2
-------t2--------对count进行+1操作
-------t2--------count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:4
-------t2--------对count进行+1操作
-------t2--------count值为:5

可以看到,由于T1先启动,所以在使用mutex.WaitOne()方法后,T1获得互斥锁mutex的所有权,这时候,T2的mutex.WaitOne()代码返回false,所以线程阻塞,必须等T1调用mutex.ReleaseMutex()后才能继续执行。


子线程的代码不变,如果我们更改一下T1,T2的启动顺序:

 static void Main(string[] args)
 {
     Thread t2= new Thread(ChangeValue);
     Thread t1 = new Thread(ShowValue);

     t2.Start();     //线程2启动
     t1.Start();     //线程1启动

     Console.WriteLine("主线程结束,请按任意键退出");
     Console.ReadKey();
 }

返回结果:

主线程结束,请按任意键退出
-------t2--------对count进行+1操作
-------t2--------count值为:1
-------t2--------对count进行+1操作
-------t2--------count值为:2
-------t2--------对count进行+1操作
-------t2--------count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:4
-------t2--------对count进行+1操作
-------t2--------count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5

可以看到,程序会先执行T2的代码段,然后在T2释放互斥锁以后,T1接着执行。


另外,互斥锁针对的是WaitOne()以及ReleaseMutex()之间的代码,而不是整个线程,Main()函数不变,我们看看下面实例:

static void ChangeValue()
{
    Console.WriteLine("T2在互斥锁以外的代码");
    mutex.WaitOne();
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("-------t2--------对count进行+1操作");
        count++;
        Console.WriteLine("-------t2--------count值为:" + count.ToString());
        Thread.Sleep(1000);
    }
    mutex.ReleaseMutex();
}

static void ShowValue()
{
    Console.WriteLine("T1在互斥锁以外的代码");
    mutex.WaitOne();
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("t1:count值为:" + count.ToString());
        Thread.Sleep(1000);
    }
    mutex.ReleaseMutex();
}

运行结果:

主线程结束,请按任意键退出
T1在互斥锁以外的代码
T2在互斥锁以外的代码
t1:count值为:0
t1:count值为:0
t1:count值为:0
t1:count值为:0
t1:count值为:0
-------t2--------对count进行+1操作
-------t2--------count值为:1
-------t2--------对count进行+1操作
-------t2--------count值为:2
-------t2--------对count进行+1操作
-------t2--------count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:4
-------t2--------对count进行+1操作
-------t2--------count值为:5

可以看到,在互斥锁以外的代码,是不受互斥锁的阻塞影响的。


Mutex(bool)

如果创建实例时,填入一个bool参数,那么表示,在创建该互斥锁的同时,会相应控制互斥锁的所有权,如果参数为True,表示创建互斥锁的线程,具有互斥锁的所有权,如果它不使用ReleaseMux()释放互斥锁的所有权,那么其他使用互斥锁的线程,将一直被阻塞。实例如下

static int count = 0;        //用于计数
static Mutex mutex = new Mutex(true);      //创建互斥锁实例并获取互斥锁所有权
static void Main(string[] args)
{
    Thread t2= new Thread(ChangeValue);
    Thread t1 = new Thread(ShowValue);

    
    t2.Start();     //线程2启动
    t1.Start();     //线程1启动

    Console.WriteLine("主线程结束,请按任意键退出");
    Console.ReadKey();
}

线程调用方法不变,运行结果:

主线程结束,请按任意键退出

由于主线程在创建时,获取了互斥锁的所有权,而主线程一直没有调用ReleaseMutex()方法,所以,同样使用了互斥锁的T1,T2一直无法执行。


这时候,如果我们在主线程的某一时刻释放了互斥锁:
 

static int count = 0;        //用于计数
static Mutex mutex = new Mutex(true);      //创建互斥锁实例并获取互斥锁所有权
static void Main(string[] args)
{
    Thread t2= new Thread(ChangeValue);
    Thread t1 = new Thread(ShowValue);

    
    t2.Start();     //线程2启动
    t1.Start();     //线程1启动

    Console.WriteLine("主线程延迟3秒释放互斥锁");
    Thread.Sleep(3000);
    mutex.ReleaseMutex();

    Console.WriteLine("主线程结束,请按任意键退出");
    Console.ReadKey();
}

运行结果:

主线程延迟3秒释放互斥锁
主线程结束,请按任意键退出
-------t2--------对count进行+1操作
-------t2--------count值为:1
-------t2--------对count进行+1操作
-------t2--------count值为:2
-------t2--------对count进行+1操作
-------t2--------count值为:3
-------t2--------对count进行+1操作
-------t2--------count值为:4
-------t2--------对count进行+1操作
-------t2--------count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5
t1:count值为:5

可以看到,主线程释放互斥锁以后,两个分线程都能正常运行。

所以,Mutex mutex=Mutex(True)等价于 Mutex mutex=Mutex()+ mutex.WaitOne()。


常用方法

WaitOne()

        获取互斥锁的所有权,如果互斥锁当前处于释放状态,执行WaitOne()后返回true,当前线程获取互斥锁所有权。如果互斥锁被其他线程占有,那么当前线程执行WaitOne()后返回false,获取互斥锁所有权失败,要继续等待拥有互斥锁的线程释放互斥锁所有权。


ReleaseMutex()

        释放互斥锁的所有权


  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值