具体用法参考示例
// 创建读写锁ReaderWriterLock rwLock = new ReaderWriterLock();
// 当前线程获取读锁,参数为:超时值(毫秒)
rwLock.AcquireReaderLock(250);
// 判断当前线程是否持有读锁
if (!rwLock.IsReaderLockHeld)
{
return;
}
Console.WriteLine("拿到了读锁......");
// 将读锁升级为写锁,锁参数为:超时值(毫秒)
LockCookie cookie = rwLock.UpgradeToWriterLock(250);
// 判断当前线程是否持有写锁
if (rwLock.IsWriterLockHeld)
{
Console.WriteLine("升级到了写锁......");
// 将锁还原到之前所的级别,也就是读锁
rwLock.DowngradeFromWriterLock(ref cookie);
}
// 释放读锁(减少锁计数,直到计数达到零时,锁被释放)
rwLock.ReleaseReaderLock();
Console.WriteLine("顺利执行完毕......");
// 当前线程获取写锁,参数为:超时值(毫秒)
rwLock.AcquireWriterLock(250);
// 判断当前线程是否持有写锁
if (rwLock.IsWriterLockHeld)
{
Console.WriteLine("拿到了写锁......");
// 释放写锁(将减少写锁计数,直到计数变为零,释放锁)
rwLock.ReleaseWriterLock();
}
// 释放写锁(将减少写锁计数,直到计数变为零,释放锁)
// 当前线程不持有锁,会抛出异常
rwLock.ReleaseWriterLock();
Console.WriteLine("顺利执行完毕......");
Console.ReadLine();
ReaderWriterLockSlim同样是ReaderWriterLock的轻量优化版本,简化了递归、升级和降级锁定状态的规则。
1. EnterWriteLock 进入写模式锁定状态
2. EnterReadLock 进入读模式锁定状态
3. EnterUpgradeableReadLock 进入可升级的读模式锁定状态
并且三种锁定模式都有超时机制、对应 Try… 方法,退出相应的模式则使用 Exit… 方法,而且所有的方法都必须是成对出现的
并行环境下修改共享变量为了保证资源安全,通常使用上面介绍的锁或信号量来解决此问题。其实.NET也内置了一些线程安全的集合,使用他们就像使用单线程集合一样。
类型 描述BlockingCollection 提供针对实现 IProducerConsumerCollection 的任何类型的限制和阻塞功能。 有关详细信息,请参阅BlockingCollection 概述。
ConcurrentDictionary<tkey,tvalue> 键/值对字典的线程安全实现。
ConcurrentQueue FIFO(先进先出)队列的线程安全实现。
ConcurrentStack LIFO(后进先出)堆栈的线程安全实现。
ConcurrentBag 无序的元素集合的线程安全实现。
IProducerConsumerCollection 类型必须实现以在 BlockingCollection 中使用的接口。
三、多线程模型 1、同步编程模型SPM 2、异步编程模型APM
我们常见的XXBegin, XXEnd这两个经典的配对方法就是异步的,Begin后会委托给线程池调用一个线程去执行。还有委托的BeginInvoke调用
FileStream fs = new FileStream("D:\\test.txt", FileMode.Open);var bytes = new byte[fs.Length];
fs.BeginRead(bytes, 0, bytes.Length, (aysc) =>
{
var num = fs.EndRead(aysc);
}, string.Empty);
3、基于事件编程模型EAP
WinFrom/WPF开发中的BackgroundWorker类就是异步事件模式的一种实现方案,RunWorkerAsync方法启动与DoWork事件异步关联的方法,工作完成后,就触发RunWorkerCompleted事件,也支持CancelAysnc方法取消以及ReportProgress通知进度等。还又一个典型的就是WebClient
WebClient client = new WebClient();client.DownloadDataCompleted += (sender,e)=>
{
};
client.DownloadDataAsync(new Uri("https://www.baidu.com/"));
4、基于任务编程模型TAP
Task出来后,微软就大力推广基于Task的异步编程模型,APM和EAP都被包装成Task使用。下面示例简单用Task封装上面的编程模型。WebClient的DownloadDataTaskAsync实现和示例中的类似,利用一个TaskCompletionSource包装器包装成Task
FileStream fs = new FileStream("D:\\test.txt", FileMode.Open);var bytes = new byte[fs.Length];
var task = Task.Factory.FromAsync(fs.BeginRead, fs.EndRead, bytes, 0, bytes.Length, string.Empty);
var nums = task.Result;
Action action = () =>{ };
var task = Task.Factory.FromAsync(action.BeginInvoke, action.EndInvoke, string.Empty);
public static Task<int> GetTaskAsuc(string url)
{
TaskCompletionSource<int> source = new TaskCompletionSource<int>();//包装器
WebClient client = new WebClient();
client.DownloadDataCompleted += (sender, e) =>
{
try
{
source.TrySetResult(e.Result.Length);
}
catch (Exception ex)
{
source.TrySetException(ex);
}
};
client.DownloadDataAsync(new Uri(url));
return source.Task;
}
四、End