我需要使现有的应用程序线程安全.在适当的情况下(见下文),我决定在整个业务对象图中使用一个ReaderWriterLock.所有方法/属性必须如下所示:
public int MyReadOperation(string inputParam) { rwLock.AcquireReaderLock(10000); try { // do all read operations ... } finally { rwLock.ReleaseReaderLock(); } } public void MyWriteOperation(string input) { rwLock.AcquireWriterLock(10000); try { // do all write operations ... } finally { rwLock.ReleaseWriterLock(); } }
但是我有很多方法可以覆盖,我从复制/粘贴的想法中吓坏了.受MethodImplAttribute的启发,我希望有一个这样的代码,同时表现为上面的代码:
[ReadOperation] public int MyReadOperation(string inputParam) { // do all read operations ... } [WriteOperation] public void MyWriteOperation(string input) { // do all write operations ... }
有没有办法在进入属性或方法之前/之后中断线程执行并添加线程安全预防措施?或者以某种方式利用C#的函数式语言特性,将方法的生产体嵌入到通用的ReaderWriterLock中获取"框架"?
一点背景:
我正在开发一个项目,通过.NET Remoting公开数据载体业务对象.但是,这些数据类不是可序列化的,而是MarshalByRef-s.这意味着所有客户端实际上读/写相同的业务对象.这是不可改变的,它是刻在石头上的.线程安全的希望是这些远程业务对象在远程客户端的眼中是只读的(认为它们会循环许多列表)并且所有写入操作都很好地分成专用的外观.我希望罕见的写入和频繁的读取.业务对象高度连接,它们非常"图形化".
我会使用PostSharp做类似的事情.
它作为一个额外的构建步骤运行并插入相应的MSIL,但它会做你想要的.PostSharp属性定义看起来像这样(取决于您的确切实现).然后可以如上所述使用它们.
public sealed class ReadOperationAttribute : OnMethodBoundaryAspect { // not quite sure how you manage your lock, so put this dummy method in. ReaderWriterLock _rwLock = ReaderWriterLock.GetCorrectReaderWriterLock(); [ThreadStatic] static bool _isLocked; public override void OnEntry( MethodExecutionEventArgs e ) { try { _rwLock.AcquireReaderLock(10000); _isLocked = true; } catch { _isLocked = false; throw; } } public override void OnExit( MethodExecutionEventArgs e ) { if (_isLocked) { _rwLock.ReleaseReaderLock(); _isLocked = false; } } } public sealed class WriteOperationAttribute : OnMethodBoundaryAspect { // not quite sure how you manage your lock, so put this dummy method in. ReaderWriterLock _rwLock = ReaderWriterLock.GetCorrectReaderWriterLock(); [ThreadStatic] static bool _isLocked; public override void OnEntry( MethodExecutionEventArgs e ) { try { _rwLock.AcquireWriterLock(10000); _isLocked = true; } catch { _isLocked = false; throw; } } public override void OnExit( MethodExecutionEventArgs e ) { if (_isLocked) { _rwLock.ReleaseReaderLock(); _isLocked = false; } } }
编辑:更新以解决问题.(未经测试;))另外,请注意我在这个问题的评论称,微软建议使用ReaderWriterLockSlim
优先于ReaderWriterLock
.
首先,谢谢安德鲁(Andrew),他把我指向了 PostSharp。根据他的回答,我得出了最后一个答案。
[Serializable] public class ReadOperationAttribute : PostSharp.Laos.OnMethodInvocationAspect { public override void OnInvocation(MethodInvocationEventArgs eventArgs) { ReaderWriterLock rwLock = GetLock(); rwLock.AcquireReaderLock(10000); try { eventArgs.Proceed(); } finally { rwLock.ReleaseReaderLock();} } } public class Foo { [ReadOperation] public string Bar { get { return "stuff"; } set { Console.WriteLine(value); } } [ReadOperation] public void Test(string input) { Console.WriteLine(input); } }
它完全符合我在问题中表达的内容,并且完全可以调试。如果我们声明整个程序集的属性,我们可以使其更加有用:
[assembly: ReadOperation(AttributeTargetElements=MulticastTargets.Method, AttributeTargetTypes="MyNamespace.*")]
这样,我们不必修饰每个方法/属性,但是将这个属性放置在程序集中一次后,便可以使用ReaderWriterLock制动所有方法/属性。
另外,正如Andrew所指出的那样,如果您使用.NET3.5或更高版本,Microsoft建议使用ReaderWriterLockSlim。