Kể từ thời điểm một khóa là để bảo vệ một số bộ nhớ, tôi nghĩ rằng nó sẽ hữu ích để bọc bộ nhớ đó trong một đối tượng "Đã khóa", và chỉ làm cho nó có thể truy cập thông qua các thẻ khóa khác nhau (như đã đề cập bởi Mark):
// Stores a private List<T>, only accessible through lock tokens
// returned by Read, Write, and UpgradableRead.
var lockedList = new LockedList<T>();
using(var r = lockedList.Read()) {
foreach(T item in r.Reader)
...
}
using(var w = lockedList.Write()) {
w.Writer.Add(new T());
}
T t = ...;
using(var u = lockedList.UpgradableRead()) {
if(!u.Reader.Contains(t))
using(var w = u.Upgrade())
w.Writer.Add(t);
}
Bây giờ cách duy nhất để truy cập vào danh sách nội bộ là bằng cách gọi accessor thích hợp.
Điều này hoạt động đặc biệt tốt cho List<T>
, vì nó đã có bao bì ReadOnlyCollection<T>
. Đối với các loại khác, bạn luôn có thể tạo ra một Locked<T,T>
, nhưng sau đó bạn bị mất trên sự phân biệt loại dễ đọc/có thể ghi.
Một cải tiến có thể là để xác định các loại R
và W
như giấy gói dùng một lần bản thân, mà sẽ được bảo vệ chống lại các lỗi (inadvertant) như:
List<T> list;
using(var w = lockedList.Write())
list = w.Writable;
//BAD: "locked" object leaked outside of lock scope
list.MakeChangesWithoutHoldingLock();
Tuy nhiên, điều này sẽ làm cho Locked
phức tạp hơn để sử dụng, và Phiên bản hiện tại cung cấp cho bạn sự bảo vệ giống như bạn có khi khóa thủ công một thành viên được chia sẻ.
sealed class LockedList<T> : Locked<List<T>, ReadOnlyCollection<T>> {
public LockedList()
: base(new List<T>(), list => list.AsReadOnly())
{ }
}
public class Locked<W, R> where W : class where R : class {
private readonly LockerState state_;
public Locked(W writer, R reader) { this.state_ = new LockerState(reader, writer); }
public Locked(W writer, Func<W, R> getReader) : this(writer, getReader(writer)) { }
public IReadable Read() { return new Readable(this.state_); }
public IWritable Write() { return new Writable(this.state_); }
public IUpgradable UpgradableRead() { return new Upgradable(this.state_); }
public interface IReadable : IDisposable { R Reader { get; } }
public interface IWritable : IDisposable { W Writer { get; } }
public interface IUpgradable : IReadable { IWritable Upgrade();}
#region Private Implementation Details
sealed class LockerState {
public readonly R Reader;
public readonly W Writer;
public readonly ReaderWriterLockSlim Sync;
public LockerState(R reader, W writer) {
Debug.Assert(reader != null && writer != null);
this.Reader = reader;
this.Writer = writer;
this.Sync = new ReaderWriterLockSlim();
}
}
abstract class Accessor : IDisposable {
private LockerState state_;
protected LockerState State { get { return this.state_; } }
protected Accessor(LockerState state) {
Debug.Assert(state != null);
this.Acquire(state.Sync);
this.state_ = state;
}
protected abstract void Acquire(ReaderWriterLockSlim sync);
protected abstract void Release(ReaderWriterLockSlim sync);
public void Dispose() {
if(this.state_ != null) {
var sync = this.state_.Sync;
this.state_ = null;
this.Release(sync);
}
}
}
class Readable : Accessor, IReadable {
public Readable(LockerState state) : base(state) { }
public R Reader { get { return this.State.Reader; } }
protected override void Acquire(ReaderWriterLockSlim sync) { sync.EnterReadLock(); }
protected override void Release(ReaderWriterLockSlim sync) { sync.ExitReadLock(); }
}
sealed class Writable : Accessor, IWritable {
public Writable(LockerState state) : base(state) { }
public W Writer { get { return this.State.Writer; } }
protected override void Acquire(ReaderWriterLockSlim sync) { sync.EnterWriteLock(); }
protected override void Release(ReaderWriterLockSlim sync) { sync.ExitWriteLock(); }
}
sealed class Upgradable : Readable, IUpgradable {
public Upgradable(LockerState state) : base(state) { }
public IWritable Upgrade() { return new Writable(this.State); }
protected override void Acquire(ReaderWriterLockSlim sync) { sync.EnterUpgradeableReadLock(); }
protected override void Release(ReaderWriterLockSlim sync) { sync.ExitUpgradeableReadLock(); }
}
#endregion
}
+1 đoạn trích tuyệt vời! –
Hài hước, tôi đã từ lâu quên mất điều này và chỉ tình cờ nó nổi lên trong danh tiếng của tôi chỉ lên khi tôi có thể hưởng lợi từ nó. –