.NET 中的声明式线程安全
我需要使现有应用程序线程安全。 由于情况(见下文),我决定对整个业务对象图使用一个 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。 这意味着所有客户端实际上读取/写入完全相同的业务对象。 这是无法改变的,是刻在石头上的。 线程安全的希望是,这些远程业务对象在远程客户端的眼中是只读的(认为它们确实循环许多列表),并且所有写入操作都很好地分离到专用的外观中。 我期望很少写入和频繁读取。 业务对象高度关联,非常“图形化”。
I need to make an existing app thread safe. Due circumstances (see below), I decided to use one single ReaderWriterLock for the entire graph of business objects. All methods/properties must look like these:
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();
}
}
But I have immense amount of methods to cover and I am freaked out from the idea of copy/pasting.
Inspired by MethodImplAttribute, I would prefer to have a code like this while behave as the code above:
[ReadOperation]
public int MyReadOperation(string inputParam)
{
// do all read operations
...
}
[WriteOperation]
public void MyWriteOperation(string input)
{
// do all write operations
...
}
Is there a way to interrupt Thread execution before/after entering into a property or a method and adding the thread-safety precautions? Or somehow utilizing the functional language features of C#, embedding the productive body of the methods into a generic ReaderWriterLock aquiring "frame"?
A bit of background:
I am working on a project where data carrier business objects are exposed via .NET Remoting. However, these data classes are not serializable but MarshalByRef-s. That means that ALL clients actually read/write the very same business objects. This cannot be changed, it is carved in stone. The hope for thread-safety is that these remoted business objects are read-only in the eyes of the remoting clients (thought they do loop many lists) and all write operations are nicely separated into a dedicated facade.
I expect rare writes and frequent reads. The business objects are highly connected, they are very "graphy".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我会使用 PostSharp 做类似的事情。
它作为额外的构建步骤运行并插入相应的 MSIL,但它会执行您想要的操作。
PostSharp 属性定义看起来像这样(取决于您的具体实现)。 然后可以按照您上面的描述使用它们。
编辑:更新以解决问题。 (未经测试;))
另外,请注意,正如我在问题评论中所说,Microsoft 建议优先使用
ReaderWriterLockSlim
而不是ReaderWriterLock
。I would do something like that using PostSharp.
It runs as an extra build step and inserts the corresponding MSIL, but it will do what you want.
The PostSharp attribute definitions would look something like this (depending on your exact implementation). These could then be used as you describe above.
EDIT: Updated to address concerns. (Untested ;) )
Also, note as I said in the comment to the question, Microsoft recommends using
ReaderWriterLockSlim
in preference toReaderWriterLock
.首先,感谢 Andrew 向我指出 PostSharp。 根据他的回答,我最终得到了最后一个。
它完全按照我在问题中表达的方式进行,并且完全可以调试。 如果我们为整个程序集声明该属性,我们可以使其变得更加有用:
这样我们就不必装饰每个方法/属性,而是将此属性放入程序集中一次,我们就可以使用 ReaderWriterLock 来制动所有方法/属性。
另外,正如 Andrew 所指出的,如果您使用 .NET3.5 或更高版本,微软建议使用 ReaderWriterLockSlim。
First of all, thanx to Andrew pointing me to PostSharp. Based on his answer, I ended up with this final one.
It does exactly what I expressed in the question and is perfectly debuggable. We can make it even more useful, if we declare the attribute for an entire assembly:
This way we do not have to decorate every method/property, but placing this attribute in the assembly once, we braket all our methods/properties with ReaderWriterLock.
Also, as it has been pointed out by Andrew, Microsoft recommends to use ReaderWriterLockSlim if you use .NET3.5 or above.
使用构建后步骤可能是一个很好的解决方案。 在纯代码中,我将在 ReaderWriterLock 上创建扩展方法,如下所示:
其中一个用于写入。 如果锁确实是全局的,您甚至可以创建静态方法。 那么你的代码看起来就不那么烦人了:
这样做的好处是细粒度,因此方法中不需要同步的部分将不会被同步。 但是,它仍然需要对每种方法进行更改。 幸运的是,它们相对较小,并且您最终要更改的所有锁定代码至少都在一个地方。
Using a post-build step might be a good solution. In pure code, I would create extension methods on ReaderWriterLock like this:
And one for write. If the lock is truely global, you could even make static methods. Then your code looks a lot less annoying:
This has the benefit of being fine-grained, so parts of a method that don't need sync'd won't be sync'd. But, it still does require making changes to each method. Fortunately they're relatively small, and all the locking code you'd end up changing is at least in one place.