.NET进阶篇06-async异步、thread多线程4 (3)

具体用法参考示例

// 创建读写锁
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<intGetTaskAsuc(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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjjgs.html