石家庄哪里能制作网站wordpress linux下载
web/
2025/9/27 1:35:10/
文章来源:
石家庄哪里能制作网站,wordpress linux下载,网站开发实习,北京海淀建筑行业培训中心传送门#xff1a;异步编程系列目录……
最近在学习.NET4.5关于“并行任务”的使用。“并行任务”有自己的同步机制#xff0c;没有显示给出类似如旧版本的#xff1a;事件等待句柄、信号量、lock、ReaderWriterLock……等同步基元对象#xff0c;但我们可以沿溪这一编程习…传送门异步编程系列目录……
最近在学习.NET4.5关于“并行任务”的使用。“并行任务”有自己的同步机制没有显示给出类似如旧版本的事件等待句柄、信号量、lock、ReaderWriterLock……等同步基元对象但我们可以沿溪这一编程习惯那么这系列翻译就是给“并行任务”封装同步基元对象。翻译资源来源《译关于Async与Await的FAQ》
1. 构建Async同步基元Part 1 AsyncManualResetEvent
2. 构建Async同步基元Part 2 AsyncAutoResetEvent
3. 构建Async同步基元Part 3 AsyncCountdownEvent
4. 构建Async同步基元Part 4 AsyncBarrier
5. 构建Async同步基元Part 5 AsyncSemaphore
6. 构建Async同步基元Part 6 AsyncLock
7. 构建Async同步基元Part 7 AsyncReaderWriterLock 源码构建Async同步基元.rar
开始构建Async同步基元Part 7 AsyncReaderWriterLock 在上一篇文章中我们构建了一个AsyncLock本文我将构建一个更高级的构造一个异步版本的读写/锁。 异步版本的读写/锁比前几篇文章中所创建的同步基元要更加复杂。它包含更多的控制这意味着需要更多决定来构建这个类型的精确行为。对于本例我做了以下决定。首先写操作比读操作拥有更高的优先级即无论读操作或写操作请求的顺序如果有写操作正在等待它将得到优先于任何数量的读操作得到处理即使它比那些读操作请求的晚些。第二我决定不对读操作限流即只要此时不存在未解决的写操作或等待着的写操作所有读操作会立马被唤醒。 这是我们将构建的目标类型 1 2 3 4 5 6 7 8 9 10 11 12 public class AsyncReaderWriterLock { public AsyncReaderWriterLock(); public TaskReleaser ReaderLockAsync(); public TaskReleaser WriterLockAsync(); public struct Releaser : IDisposable { public void Dispose(); } } 就像AsyncLock一样我们使用一个实现IDiposable接口的Releaser结构使AsyncReaderWriterLock类型能轻易用于一个范围例如 1 2 3 4 5 6 private readonly AsyncReaderWriterLock m_lock new AsyncReaderWriterLock(); … using(var releaser await m_lock.ReaderLockAsync()) { … // protected code here } 现在构建Releaser结构我们使用一个bool值类型变量标识是否是写操作因为我们需要使用不同的方式来唤醒两种操作的锁优先处理写操作。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public struct Releaser : IDisposable { private readonly AsyncReaderWriterLock m_toRelease; private readonly bool m_writer; internal Releaser(AsyncReaderWriterLock toRelease, bool writer) { m_toRelease toRelease; m_writer writer; } public void Dispose() { if (m_toRelease ! null) { if (m_writer) m_toRelease.WriterRelease(); else m_toRelease.ReaderRelease(); } } } 因为AsyncReaderWriterLock比前几篇文章中所创建的同步基元要更加复杂所以我需要更多成员变量。首先我们为了提高性能我为读操作的等待缓存了一个TaskReleaser同时也为写操作的等待缓存了一个TaskReleaser以便立即完成。 1 2 3 4 5 6 7 private readonly TaskReleaser m_readerReleaser; private readonly TaskReleaser m_writerReleaser; public AsyncReaderWriterLock() { m_readerReleaser Task.FromResult(new Releaser(this, false)); m_writerReleaser Task.FromResult(new Releaser(this, true)); } 接下来我需要为写操作维护一个等待队列对于每一个写操作等待者都有对应的TaskCompletionSource实例因为我需要支持单独唤醒它们。同样也需要为读操作维护一个TaskCompletionSourceReleaser实例。然而对于读操作按我们之前谈论的设计当允许读操作运行时就能让所有读操作一起运行因此我只需要一个TaskCompletionSourceReleaser实例。然而因为我为读操作只维护了一个TaskCompletionSourceReleaser实例所以我还需要知道有多少个读操作正在等待以便当我最终唤醒它们时我能确保所有读操作被唤醒。 1 2 3 4 5 private readonly QueueTaskCompletionSourceReleaser m_waitingWriters new QueueTaskCompletionSourceReleaser(); private TaskCompletionSourceReleaser m_waitingReader new TaskCompletionSourceReleaser(); private int m_readersWaiting; 最后我需要一个变量来维护锁的当前状态它是一个整型数值为0表示锁空闲数值为-1表示一个写操作获取锁正值表示一个或多个读操作获取锁。 1 private int m_status; 现在我们来实现4个方法ReaderLockAsync, ReaderRelease, WriterLockAsync, and WriterRelease。为了保证这4个方法数据的同步我们首先对m_waitingWriters加锁
ReaderLockAsync()方法用于读操作获取锁。在对m_waitingWriters加独占锁后我们需要决定读操作是应该立即响应还是应该被迫等待。正如前面的决策如果当前不存在等待的写操作或正在执行写操作则读操作能立即得到响应这种情况下我们递增m_status计数并且返回为读操作缓存的TaskCompletionSourceReleaser实例。如果当前存在等待的写操作或正在执行写操作则我们强迫读操作等待我们递增m_readersWaiting计数并且为读操作缓存的TaskCompletionSourceReleaser实例添加延续任务并返回延续任务确保所有的等待者能并发运行而不是串行化。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public TaskReleaser ReaderLockAsync() { lock (m_waitingWriters) { if (m_status 0 m_waitingWriters.Count 0) { m_status; return m_readerReleaser; } else { m_readersWaiting; return m_waitingReader.Task.ContinueWith(t t.Result); } } } WriterLockAsync()用于写操作获取锁。就像ReaderLockAsync()方法一样需要对m_waitingWriters加独占锁并且要考虑两种情况写操作要么立即被响应要么被迫等待。只有当前锁是空闲状态写操作才能立即被响应因为写操作不能和任意读操作或其他写操作同时运行。所以如果m_status值为0我们更改m_status为-1表示现在正在运行一个写操作并且返回为写操作缓存的QueueTaskCompletionSourceReleaser队列。否则我们为写操作创建一个新的TaskCompletionSourceReleaser实例插入到队列中并且返回此实例对应的Task。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public TaskReleaser WriterLockAsync() { lock (m_waitingWriters) { if (m_status 0) { m_status -1; return m_writerReleaser; } else { var waiter new TaskCompletionSourceReleaser(); m_waitingWriters.Enqueue(waiter); return waiter.Task; } } } 现在我们来构建唤醒功能这些功能在被激活的读操作或写操作完成工作并且想释放它们持有的锁时被调用。ReaderRelease()需要递减读操作激活数计数并且检查当前锁的状态。如果此时唤醒的是最后一个激活的读操作并且存在写操作正在等待则会唤醒一个写操作并且设置m_status值为-1标识写操作获得锁。我们不需要检查任何等待的读操作因为写操作比任何数量的读操作优先得到处理。如果此时没有任何等待的写操作则任一后续请求的读操作将立即被响应。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void ReaderRelease() { TaskCompletionSourceReleaser toWake null; lock (m_waitingWriters) { --m_status; if (m_status 0 m_waitingWriters.Count 0) { m_status -1; toWake m_waitingWriters.Dequeue(); } } if (toWake ! null) toWake.SetResult(new Releaser(this, true)); } 最后我们构建WriterRelease()方法。当读操作完成时如果等待队列中存在等待的写操作我们从队列中取出一个写操作并且完成任务因为将激活一个新的写操作旧的写操作完成后新的写操作会取代它的位置所以不需要更新锁的状态m_status。如果等待队列中不存在等待的写操作但是此时存在等待的读操作我们会唤醒所有读操作对应的任务在这种情况下我们还要为后续的读操作创建一个新的等待任务并且需要更新m_status为当前激活的读操作数。如果没有任何读操作或写操作则我们重置锁状态m_status。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private void WriterRelease() { TaskCompletionSourceReleaser toWake null; bool toWakeIsWriter false; lock (m_waitingWriters) { if (m_waitingWriters.Count 0) { toWake m_waitingWriters.Dequeue(); toWakeIsWriter true; } else if (m_readersWaiting 0) { toWake m_waitingReader; m_status m_readersWaiting; m_readersWaiting 0; m_waitingReader new TaskCompletionSourceReleaser(); } else m_status 0; } if (toWake ! null) toWake.SetResult(new Releaser(this, toWakeIsWriter)); } 这就是本节要讲的AsyncReaderWriterLock。
完整源码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 /// summary /// Async版的 read/writer 锁 /// /summary public class AsyncReaderWriterLock { // 为了提高性能我为读/写操作的等待各缓存了一个TaskReleaser private readonly TaskReleaser m_readerReleaser; private readonly TaskReleaser m_writerReleaser; // 写操作的等待队列 private readonly QueueTaskCompletionSourceReleaser m_waitingWriters new QueueTaskCompletionSourceReleaser(); // 读操作的等待任务 private TaskCompletionSourceReleaser m_waitingReader new TaskCompletionSourceReleaser(); // 当前有多少个等待着的读操作计数 private int m_readersWaiting; // 维护锁的当前状态。0表示锁空闲-1表示一个写操作获取锁正值表示一个或多个读操作获取锁。 private int m_status; public AsyncReaderWriterLock() { m_readerReleaser Task.FromResult(new Releaser(this, false)); m_writerReleaser Task.FromResult(new Releaser(this, true)); } /// summary /// 读操作获取锁 /// /summary public TaskReleaser ReaderLockAsync() { lock (m_waitingWriters) { if (m_status 0 m_waitingWriters.Count 0) { m_status; return m_readerReleaser; } else { // 存在等待的写操作或正在执行写操作 m_readersWaiting; return m_waitingReader.Task.ContinueWith(t t.Result); } } } /// summary /// 释放读操作 /// /summary private void ReaderRelease() { TaskCompletionSourceReleaser toWake null; lock (m_waitingWriters) { --m_status; if (m_status 0 m_waitingWriters.Count 0) { // 唤醒的是最后一个激活的读操作并且存在写操作正在等待 m_status -1; toWake m_waitingWriters.Dequeue(); } } if (toWake ! null) toWake.SetResult(new Releaser(this, true)); } /// summary /// 写操作获取锁 /// /summary public TaskReleaser WriterLockAsync() { lock (m_waitingWriters) { if (m_status 0) { m_status -1; return m_writerReleaser; } else { // 新的写操作被迫等待 var waiter new TaskCompletionSourceReleaser(); m_waitingWriters.Enqueue(waiter); return waiter.Task; } } } /// summary /// 释放写操作 /// /summary private void WriterRelease() { TaskCompletionSourceReleaser toWake null; bool toWakeIsWriter false; lock (m_waitingWriters) { if (m_waitingWriters.Count 0) { toWake m_waitingWriters.Dequeue(); toWakeIsWriter true; } else if (m_readersWaiting 0) { toWake m_waitingReader; m_status m_readersWaiting; m_readersWaiting 0; m_waitingReader new TaskCompletionSourceReleaser(); } else m_status 0; } if (toWake ! null) toWake.SetResult(new Releaser(this, toWakeIsWriter)); } public struct Releaser : IDisposable { private readonly AsyncReaderWriterLock m_toRelease; // 变量标识是否是写操作因为我们需要使用不同的方式来释放两种操作的锁 private readonly bool m_writer; internal Releaser(AsyncReaderWriterLock toRelease, bool writer) { m_toRelease toRelease; m_writer writer; } public void Dispose() { if (m_toRelease ! null) { if (m_writer) m_toRelease.WriterRelease(); else m_toRelease.ReaderRelease(); } } } } /// summary /// 示例AsyncReaderWriterLock /// /summary public class AsyncReaderWriterLockTest { public static async void Test() { AsyncReaderWriterLock m_lock new AsyncReaderWriterLock(); using (var releaser await m_lock.WriterLockAsync()) { } using (var releaser await m_lock.ReaderLockAsync()) { } } } 推荐阅读 异步编程同步基元对象上 异步编程同步基元对象下 构建Async版本的同步基元系列已经全部翻译完我希望你喜欢它。感谢大家的观看……赞的话请多帮推荐(*^_^*)
原文《Building Async Coordination Primitives, Part 7: AsyncReaderWriterLock》
作者Stephen Toub – MSFT
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/82472.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!