互斥锁:Monitor 和 mutex
定义:private static readonly object Lock = new object();
使用:Monitor.Enter(Lock); //todo Monitor.Exit(Lock);
作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。
注意:定义的锁对象应该是 私有的,静态的,只读的,引用类型的对象,这样可以防止外部改变锁对象
Monitor有TryEnter的功能,可以防止出现死锁的问题,lock没有
定义:private static readonly Mutex mutex = new Mutex();
使用:mutex.WaitOne(); //todo mutex.ReleaseMutex();
作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。
注意:定义的锁对象应该是 私有的,静态的,只读的,引用类型的对象,这样可以防止外部改变锁对象
Mutex本身是可以系统级别的,所以是可以跨越进程的
Monitor 测试实现:
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sample5_2_monitor_lock
{
class Program
{
private static int _TaskNum = 3;
private static Task[] _Tasks;
private static StringBuilder _StrBlder;
private const int RUN_LOOP = 50;
private static void Work1(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} =====\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.Enter(_StrBlder, ref lockToken);
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
private static void Work2(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} *****\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.Enter(_StrBlder, ref lockToken);
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
private static void Work3(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} ~~~~~\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.Enter(_StrBlder, ref lockToken);
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
static void Main(string[] args)
{
_Tasks = new Task[_TaskNum];
_StrBlder = new StringBuilder();
_Tasks[0] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work1(taskid);
}, 0);
_Tasks[1] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work2(taskid);
}, 1);
_Tasks[2] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work3(taskid);
}, 2);
var finalTask = Task.Factory.ContinueWhenAll(_Tasks, (tasks) =>
{
Task.WaitAll(_Tasks);
Console.WriteLine("==========================================================");
Console.WriteLine("All Phase is completed");
Console.WriteLine("==========================================================");
Console.WriteLine(_StrBlder);
});
try
{
finalTask.Wait();
}
catch (AggregateException aex)
{
Console.WriteLine("Task failed And Canceled" + aex.ToString());
}
finally
{
}
Console.ReadLine();
}
}
}
锁超时的使用:
其中主要使用的是 Monitor.TryEnter(),函数,其中多了一个设置超时时间的参数。
代码中让每个锁的超时Timer为2秒,在Work1中挺顿5秒,这样造成了Work2和Work3的超时。
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sample5_3_monitor_lock_timeout
{
class Program
{
private static int _TaskNum = 3;
private static Task[] _Tasks;
private static StringBuilder _StrBlder;
private const int RUN_LOOP = 50;
private static void Work1(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} =====\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.TryEnter(_StrBlder, 2000, ref lockToken);
if (!lockToken)
{
Console.WriteLine("Work1 TIMEOUT!! Will throw Exception");
throw new TimeoutException("Work1 TIMEOUT!!");
}
System.Threading.Thread.Sleep(5000);
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
private static void Work2(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} *****\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.TryEnter(_StrBlder, 2000, ref lockToken);
if (!lockToken)
{
Console.WriteLine("Work2 TIMEOUT!! Will throw Exception");
throw new TimeoutException("Work2 TIMEOUT!!");
}
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
private static void Work3(int TaskID)
{
int i = 0;
string log = "";
bool lockToken = false;
while (i < RUN_LOOP)
{
log = String.Format("Time: {0} Task : #{1} Value: {2} ~~~~~\n",
DateTime.Now.TimeOfDay, TaskID, i);
i++;
try
{
lockToken = false;
Monitor.TryEnter(_StrBlder, 2000, ref lockToken);
if (!lockToken)
{
Console.WriteLine("Work3 TIMEOUT!! Will throw Exception");
throw new TimeoutException("Work3 TIMEOUT!!");
}
_StrBlder.Append(log);
}
finally
{
if (lockToken)
Monitor.Exit(_StrBlder);
}
}
}
static void Main(string[] args)
{
_Tasks = new Task[_TaskNum];
_StrBlder = new StringBuilder();
_Tasks[0] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work1(taskid);
}, 0);
_Tasks[1] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work2(taskid);
}, 1);
_Tasks[2] = Task.Factory.StartNew((num) =>
{
var taskid = (int)num;
Work3(taskid);
}, 2);
var finalTask = Task.Factory.ContinueWhenAll(_Tasks, (tasks) =>
{
Task.WaitAll(_Tasks);
Console.WriteLine("==========================================================");
Console.WriteLine("All Phase is completed");
Console.WriteLine("==========================================================");
Console.WriteLine(_StrBlder);
});
try
{
finalTask.Wait();
}
catch (AggregateException aex)
{
Console.WriteLine("Task failed And Canceled" + aex.ToString());
}
finally
{
}
Console.ReadLine();
}
}
}
mutex 测试实现 :
1、initiallyOwned表示创建mutex的线程是否拥有该互斥体。true表示创建线程拥有互斥锁,只有在创建线程中调用ReleaseMutex释放后,其他等待线程才能参与抢夺互斥体的活动。false表示互斥锁体于与空闲状态,其他等待互斥锁的线程立即参与到抢夺互斥锁的活动中去。
2、在上面程序中如果创建mutex时使用true参数,故在启动其他线程后必须执行mutex.ReleaseMutex(),如果不释放mutex,则其他线程将一直等待下去。使用ture,相当于一创建就使用waitone()
3、mutex.WaitOne()与mutex.ReleaseMutex()要像 { } 一样配对使用,否则将出现 “由于出现被放弃的 mutex,等待过程结束” 的异常
4、mutex与monitor相比,没有暂时释放的功能;因此mutex一经释放,原释放资源的线程也将重新参与新一轮对mutex的争夺过程。
using (var mutex = new Mutex(false, "name"))
{
try
{
mutex.WaitOne();
//do something
}
catch(Exception ex)
{
throw ex;
}
finally
{
mutex.ReleaseMutex();
}
}
简单例子:实现递归
//递归里的锁变量不相干
public static class RecursiveSample
{
private static readonly Mutex Lock = new Mutex();
private static int _counterA = 0;
private static int _counterB = 0;
public static void IncrementCounterA()
{
// 获取锁
Lock.WaitOne();
try
{
_counterA++;
_counterB++;
}
finally
{
// 释放锁
Lock.ReleaseMutex();
}
}
public static void IncrementCounterB()
{
// 获取锁
Lock.WaitOne();
try
{
_counterA++;
_counterB++;
}
finally
{
// 释放锁
Lock.ReleaseMutex();
}
}
public static void IncrementCounter()
{
// 获取锁
Lock.WaitOne();
try
{
IncrementCounterA();
IncrementCounterB();
}
finally
{
// 释放锁
Lock.ReleaseMutex();
}
}
}