博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转]C#多线程学习(六) 互斥对象
阅读量:6341 次
发布时间:2019-06-22

本文共 3826 字,大约阅读时间需要 12 分钟。

如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类。

我们可以把Mutex看作一个出租车,乘客看作线程。乘客首先等车,然后上车,最后下车。当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车。而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都只有等待。

下面这个例子使用了Mutex对象来同步四个线程,主线程等待四个线程的结束,而这四个线程的运行又是与两个Mutex对象相关联的。

其中还用到AutoResetEvent类的对象,可以把它理解为一个信号灯。这里用它的有信号状态来表示一个线程的结束。

// AutoResetEvent.Set()方法设置它为有信号状态
// AutoResetEvent.Reset()方法设置它为无信号状态
Mutex 类的程序示例:

using
 System;
using
 System.Threading;
namespace
 ThreadExample
{
    
public
 
class
 MutexSample
    {
    
static
 Mutex gM1;
    
static
 Mutex gM2;
    
const
 
int
 ITERS 
=
 
100
;
    
static
 AutoResetEvent Event1 
=
 
new
 AutoResetEvent(
false
);
    
static
 AutoResetEvent Event2 
=
 
new
 AutoResetEvent(
false
);
    
static
 AutoResetEvent Event3 
=
 
new
 AutoResetEvent(
false
);
    
static
 AutoResetEvent Event4 
=
 
new
 AutoResetEvent(
false
);
    
public
 
static
 
void
 Main(String[] args)
    {
            Console.WriteLine(
"
Mutex Sample 
"
);
            
//
创建一个Mutex对象,并且命名为MyMutex
            gM1 
=
 
new
 Mutex(
true
,
"
MyMutex
"
);
            
//
创建一个未命名的Mutex 对象.
            gM2 
=
 
new
 Mutex(
true
);
            Console.WriteLine(
"
 - Main Owns gM1 and gM2
"
);
            AutoResetEvent[] evs 
=
 
new
 AutoResetEvent[
4
];
            evs[
0
=
 Event1; 
//
为后面的线程t1,t2,t3,t4定义AutoResetEvent对象
            evs[
1
=
 Event2; 
            evs[
2
=
 Event3; 
            evs[
3
=
 Event4; 
            MutexSample tm 
=
 
new
 MutexSample( );
            Thread t1 
=
 
new
 Thread(
new
 ThreadStart(tm.t1Start));
            Thread t2 
=
 
new
 Thread(
new
 ThreadStart(tm.t2Start));
            Thread t3 
=
 
new
 Thread(
new
 ThreadStart(tm.t3Start));
            Thread t4 
=
 
new
 Thread(
new
 ThreadStart(tm.t4Start));
            t1.Start( );
//
 使用Mutex.WaitAll()方法等待一个Mutex数组中的对象全部被释放
            t2.Start( );
//
 使用Mutex.WaitOne()方法等待gM1的释放
            t3.Start( );
//
 使用Mutex.WaitAny()方法等待一个Mutex数组中任意一个对象被释放
            t4.Start( );
//
 使用Mutex.WaitOne()方法等待gM2的释放
            Thread.Sleep(
2000
);
            Console.WriteLine(
"
 - Main releases gM1
"
);
            gM1.ReleaseMutex( ); 
//
线程t2,t3结束条件满足
            Thread.Sleep(
1000
);
            Console.WriteLine(
"
 - Main releases gM2
"
);
            gM2.ReleaseMutex( ); 
//
线程t1,t4结束条件满足
            
//
等待所有四个线程结束
            WaitHandle.WaitAll(evs); 
            Console.WriteLine(
"
 Mutex Sample
"
);
            Console.ReadLine();
    }
    
public
 
void
 t1Start( )
    {
            Console.WriteLine(
"
t1Start started, Mutex.WaitAll(Mutex[])
"
);
            Mutex[] gMs 
=
 
new
 Mutex[
2
];
            gMs[
0
=
 gM1;
//
创建一个Mutex数组作为Mutex.WaitAll()方法的参数
            gMs[
1
=
 gM2;
            Mutex.WaitAll(gMs);
//
等待gM1和gM2都被释放
            Thread.Sleep(
2000
);
            Console.WriteLine(
"
t1Start finished, Mutex.WaitAll(Mutex[]) satisfied
"
);
            Event1.Set( ); 
//
线程结束,将Event1设置为有信号状态
      }
    
public
 
void
 t2Start( )
    {
            Console.WriteLine(
"
t2Start started, gM1.WaitOne( )
"
);
            gM1.WaitOne( );
//
等待gM1的释放
            Console.WriteLine(
"
t2Start finished, gM1.WaitOne( ) satisfied
"
);
            Event2.Set( );
//
线程结束,将Event2设置为有信号状态
      }
    
public
 
void
 t3Start( )
    {
            Console.WriteLine(
"
t3Start started, Mutex.WaitAny(Mutex[])
"
);
            Mutex[] gMs 
=
 
new
 Mutex[
2
];
            gMs[
0
=
 gM1;
//
创建一个Mutex数组作为Mutex.WaitAny()方法的参数
            gMs[
1
=
 gM2;
            Mutex.WaitAny(gMs);
//
等待数组中任意一个Mutex对象被释放
            Console.WriteLine(
"
t3Start finished, Mutex.WaitAny(Mutex[])
"
);
            Event3.Set( );
//
线程结束,将Event3设置为有信号状态
      }
    
public
 
void
 t4Start( )
    {
            Console.WriteLine(
"
t4Start started, gM2.WaitOne( )
"
);
            gM2.WaitOne( );
//
等待gM2被释放
            Console.WriteLine(
"
t4Start finished, gM2.WaitOne( )
"
);
            Event4.Set( );
//
线程结束,将Event4设置为有信号状态
      }
    }
}

程序的输出结果:

Mutex Sample 
 - Main Owns gM1 and gM2
t1Start started, Mutex.WaitAll(Mutex[])
t2Start started, gM1.WaitOne( )
t3Start started, Mutex.WaitAny(Mutex[])
t4Start started, gM2.WaitOne( )
 - Main releases gM1
t2Start finished, gM1.WaitOne( ) satisfied
t3Start finished, Mutex.WaitAny(Mutex[])
 - Main releases gM2
t1Start finished, Mutex.WaitAll(Mutex[]) satisfied
t4Start finished, gM2.WaitOne( )
 Mutex Sample

从执行结果可以很清楚地看到,线程t2,t3的运行是以gM1的释放为条件的,而t4在gM2释放后开始执行,t1则在gM1和gM2都被释放了之后才执行。Main()函数最后,使用WaitHandle等待所有的AutoResetEvent对象的信号,这些对象的信号代表相应线程的结束。

 

文章来源:

转载于:https://www.cnblogs.com/yuanyl/p/3234348.html

你可能感兴趣的文章
研究音频编解码要看什么书
查看>>
tomcat远程调试配置
查看>>
QuartZ Cron表达式
查看>>
性能测试工具VTune的功能和用法介绍
查看>>
音频视频组件Audio DJ Studio for .NET更新至v10.0.0.0丨附下载
查看>>
RMAN Complete Recovery
查看>>
[ CodeForces 1064 B ] Equations of Mathematical Magic
查看>>
NYOJ-15:括号匹配(二)
查看>>
首次记录在案的
查看>>
C#进阶系列——WebApi 跨域问题解决方案:CORS
查看>>
错误:“产品订单的调度参数没有被定义”
查看>>
机器视觉在带钢针孔检测中的应用
查看>>
ASP.NET WEB API 调试
查看>>
使用wget命令进行整站下载
查看>>
解读volatile
查看>>
zookeeper安装部署
查看>>
centos6——初始化脚本
查看>>
linux I/O优化 磁盘读写参数设置
查看>>
中断处理 I/O内存
查看>>
Java中的transient关键字
查看>>