在C#中,以下获取/重置对线程安全吗?
请查看以下代码:在C#中,以下获取/重置对线程安全吗?,c#,multithreading,C#,Multithreading,请查看以下代码: 公共密封类Foo:IDisposable 其中T:IDisposable,new() { 公共酒吧 { 获取{return\u bar;} } 公共无效重置() { var oldBar=_bar; 使用(oldBar) { _bar=新的T(); } } 公共空间处置() { //待办事项: } 私有T_bar=新T(); } 考虑多线程环境Bargetter和Reset方法。是否保证客户端永远不会通过Bar属性获得已处置的T对象Foo对象保证不会在此时被处置。如果没有,如
公共密封类Foo:IDisposable
其中T:IDisposable,new()
{
公共酒吧
{
获取{return\u bar;}
}
公共无效重置()
{
var oldBar=_bar;
使用(oldBar)
{
_bar=新的T();
}
}
公共空间处置()
{
//待办事项:
}
私有T_bar=新T();
}
考虑多线程环境<正在从多个线程调用code>Bargetter和Reset
方法。是否保证客户端永远不会通过Bar
属性获得已处置的T
对象Foo
对象保证不会在此时被处置。如果没有,如何做对?如果可能的话,我想使用低锁技术
先谢谢你
更新
谢谢大家的帮助。这个问题需要澄清。我想要
Foo
管理Bar
状态李>
T
对象public sealed class Foo<T> : IDisposable
where T : class, IDisposable, new()
{
public bool TryExecute(Action<T> action)
{
lock (_sync)
{
if (_bar == null)
{
return false;
}
action(_bar);
return true;
}
}
public void Reset()
{
lock (_sync)
{
if (_bar == null)
{
throw new ObjectDisposedException(string.Empty);
}
Reset(new T());
}
}
public void Dispose()
{
lock (_sync)
{
if (_bar != null)
{
Reset(null);
}
}
}
private void Reset(T newBar)
{
var oldBar = _bar;
using (oldBar)
{
_bar = newBar;
}
}
private T _bar = new T();
private readonly object _sync = new object();
}
公共密封类Foo:IDisposable
其中T:class,IDisposable,new()
{
公共业务执行(行动)
{
锁定(同步)
{
如果(_bar==null)
{
返回false;
}
动作(_bar);
返回true;
}
}
公共无效重置()
{
锁定(同步)
{
如果(_bar==null)
{
抛出新的ObjectDisposedException(string.Empty);
}
重置(新T());
}
}
公共空间处置()
{
锁定(同步)
{
如果(_bar!=null)
{
重置(空);
}
}
}
私人无效重置(T纽巴)
{
var oldBar=_bar;
使用(oldBar)
{
_巴=纽巴;
}
}
私有T_bar=新T();
私有只读对象_sync=新对象();
}
我相信这次它是线程安全的。我想说的是,只通过bar属性使用_-bar变量,不要直接使用它。在工具栏上的set属性上设置一个锁。代码如下:
public sealed class Foo<T> : IDisposable
where T : IDisposable, new()
{
private readOnly object key;
public Foo(){
key = new Object();
this.Bar = new T();
}
public T Bar
{
get { return _bar; }
private set {
lock(key){
_bar = value;
}
}
}
public void Reset()
{
var oldBar = _bar;
this.Bar = new T();
}
public void Dispose()
{
this.Bar = null;
}
private T _bar;
}
公共密封类Foo:IDisposable
其中T:IDisposable,new()
{
私有只读对象密钥;
公共食物({
key=新对象();
this.Bar=新的T();
}
公共酒吧
{
获取{return\u bar;}
私有集{
锁(钥匙){
_bar=值;
}
}
}
公共无效重置()
{
var oldBar=_bar;
this.Bar=新的T();
}
公共空间处置()
{
this.Bar=null;
}
私人酒吧;;
}
您无法获得所有要求,但至少您可以使重置
本身在没有锁的情况下实现线程安全。实际上,它可能会失败,因为多个并发调用可能会尝试处置同一对象
您不能阻止客户端存储对以前t实例的引用
您可以做的是,确保每次只有一个Reset
调用可以使用更改存储的值。这还允许其中一个调用处理旧值。原始代码将失败,因为所有并发调用都可能尝试处理相同的旧值。使用compareeexchange
我们可以自动交换新旧值:
public void Reset()
{
var originalValue=_bar;
var replaced=Interlocked.CompareExchange(ref _bar,new T(),originalValue);
if(replaced!=_bar)
{
//We got to replace the value,
//we could dispose it safely if we wanted to
if (replaced!=null)
{
replaced.Dispose();
}
}
}
与oldValue
的比较意味着,即使两个线程同时执行Reset
,也只允许其中一个线程分配给\u bar
,并能够处理旧值。另一个将看到\u bar
有一个新值
这并不能解决多个临时对象的问题,而且无论如何,我们不想处理这些临时对象
如果Reset
接受一个具有替换值的参数,那么它就不必自己创建新对象,这会更容易
public void Reset(T newValue)
{
var originalValue=_bar;
var replaced=Interlocked.CompareExchange(ref _bar,newValue,originalValue);
...
}
如果不说明它将如何使用,我们无法回答您的问题。您还删除了
oldBar.Dispose()代码>从重置方法。写线程安全的代码很难。编写不使用锁的线程安全代码几乎是不可能的。我会先编写一个能正确使用锁的程序,然后再看看这是否会导致性能问题,需要解决。我的猜测是不会的。如果没有某种同步代码,就不可能保证您所要求的内容。我已经意识到,使用提供的API设计实际上是不可能做到的。。客户会将对T的引用兑现,并且无法确定它在处置后是否不会使用。@alpinsky您需要澄清您想要做什么。可以在不使用锁的情况下使Reset()
线程安全。这与确保客户端获得的条不被处理无关。也许你根本不应该关心这件事——你真的想急切地处理条形码吗?请在投票否决它之前发表评论。首先,OP要求使用低锁技术。第二,直接或通过属性使用字段应该无关紧要——除非在这种情况下,这样做会导致两次尝试获取相同的锁。此代码将死锁。这不能回答考虑多线程环境的问题。正在从多个线程调用Bar getter和Reset方法。是否保证客户端永远不会通过Bar属性获得已处置的T对象?另外,您的代码没有任何改进。哦,是的,两个锁可能会导致死锁。我拿走了一个。检查一下,现在能用吗?没有锁是不可能的。锁定setter不是问题——引用分配已经是原子的了