Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中,以下获取/重置对线程安全吗?_C#_Multithreading - Fatal编程技术网

在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
    状态
  • 确保客户端不会使用disposed
    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不是问题——引用分配已经是原子的了