Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.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#_.net_Multithreading_Thread Safety_Task Parallel Library - Fatal编程技术网

C# 实例化新实例是否使所有代码都是线程安全的?

C# 实例化新实例是否使所有代码都是线程安全的?,c#,.net,multithreading,thread-safety,task-parallel-library,C#,.net,Multithreading,Thread Safety,Task Parallel Library,编辑代码以使其成为线程安全的帖子评论 请参见最后更新的问题 你能帮我理解这个代码是否是线程安全的,或者如何使它成为线程安全的吗 设置 我的系统有一个非常简单的类叫WorkItem public class WorkItem { public int Id {get;set;} public string Name {get;set;} public DateTime DateCreated {get;set;} public IList<object>

编辑代码以使其成为线程安全的帖子评论

请参见最后更新的问题


你能帮我理解这个代码是否是线程安全的,或者如何使它成为线程安全的吗

设置

我的系统有一个非常简单的类叫WorkItem

public class WorkItem
{
    public int Id {get;set;}
    public string Name {get;set;}
    public DateTime DateCreated {get;set;}
    public IList<object> CalculatedValues {get;set;}    
}
假设我们有两个ICalculator的实现

public class BasicCalculator: ICalculator
{
    public bool Calculate(WorkItem WorkItem)
    {
        //calculate some value on the WorkItem and populate CalculatedValues property 
        return true;
    }
}
public class BasicCalculator: ICalculator
{
    public IList<object>Calculate(WorkItem WorkItem)
    {
        //calculate some value and return List<object>
        return List<object>{"A", 1};
    }
}
另一个计算器:

public class AnotherCalculator: ICalculator
{
    public bool Calculate(WorkItem WorkItem)
    {
        //calculate some value on the WorkItem and populate CalculatedValues property
        //some complex calculation on work item
        if (somevalue==0) return false;
        return true;
    }
}
public class AnotherCalculator: ICalculator
{
    public bool Calculate(WorkItem WorkItem)
    {
        //calculate some value and return List<object>
        return List<object>{"A", 1, workItem.Name};
    }
}
有一个计算器处理程序类。它的职责是按顺序执行计算器

public class CalculatorHandler
{
    public bool ExecuteAllCalculators(WorkItem task, ICalculator[] calculators)
    {
        bool final = true;
        //call all calculators in a loop
        foreach(var calculator in calculators)
        {
            var calculatedValue = calculator.Calculate(WorkItem);
            final = final && calculatedValue;           
        }
        
        return final;
    }   
}
最后,在我的客户机类中,我注入了与运行相关的ICalculators[]。然后我实例化ExecuteCalculators()方法

现在我有大量的工作项,我想对它们执行计算,所以我创建了一个任务列表,其中每个任务负责实例化CalculatorHandler实例,然后获取一个工作项并通过对所有任务执行WaitAll()来执行计算,例如

public class Client
{
    private ICalculators[] _myCalculators;
    
    public Client(ICalculators[] calculators)
    {
        _myCalculators = calculators;   
    }
    
    public void ExecuteCalculators()
    {
        var list = new List<Task>();
        for(int i =0; i <10;i++)
        {
            Task task = new Task(() => 

                var handler = new CalculatorHandler();
            
                var WorkItem = new WorkItem(){
                    Id=i,
                    Name="TestTask",
                    DateCreated=DateTime.Now
                };

                var result = handler.ExecuteAllCalculators(WorkItem, _myCalculators);
            );
            list.Add(task);
        }
        
        Task.WaitAll(list);
    }
}
public class Client
{
    
    public void ExecuteCalculators()
    {
        var list = new List<Task>();
        for(int i =0; i <10;i++)
        {
            Task task = new Task(() => 
                
                //new handler instance and new calculator instances
                var handler = new CalculatorHandler(new[]{
                  new BasicCalculator(), new AnotherCalculator()
                });
            
                var WorkItem = new WorkItem(
                    i,
                    "TestTask",
                    DateTime.Now
                };

                var result = handler.ExecuteAllCalculators(WorkItem);
            );
            list.Add(task);
        }
        
        Task.WaitAll(list);
    }
}
最后,在我的客户机类中,我执行CalculatorHandler

现在我有大量的工作项,我想对它们执行计算,所以我创建了一个任务列表,其中每个任务负责实例化CalculatorHandler实例,然后获取一个工作项并通过对所有任务执行WaitAll()来执行计算,例如

public class Client
{
    private ICalculators[] _myCalculators;
    
    public Client(ICalculators[] calculators)
    {
        _myCalculators = calculators;   
    }
    
    public void ExecuteCalculators()
    {
        var list = new List<Task>();
        for(int i =0; i <10;i++)
        {
            Task task = new Task(() => 

                var handler = new CalculatorHandler();
            
                var WorkItem = new WorkItem(){
                    Id=i,
                    Name="TestTask",
                    DateCreated=DateTime.Now
                };

                var result = handler.ExecuteAllCalculators(WorkItem, _myCalculators);
            );
            list.Add(task);
        }
        
        Task.WaitAll(list);
    }
}
public class Client
{
    
    public void ExecuteCalculators()
    {
        var list = new List<Task>();
        for(int i =0; i <10;i++)
        {
            Task task = new Task(() => 
                
                //new handler instance and new calculator instances
                var handler = new CalculatorHandler(new[]{
                  new BasicCalculator(), new AnotherCalculator()
                });
            
                var WorkItem = new WorkItem(
                    i,
                    "TestTask",
                    DateTime.Now
                };

                var result = handler.ExecuteAllCalculators(WorkItem);
            );
            list.Add(task);
        }
        
        Task.WaitAll(list);
    }
}
公共类客户端
{
public void ExecuteCalculators()
{
var list=新列表();
对于(int i=0;i
//新处理程序实例和新计算器实例
var handler=new CalculatorHandler(new[]{
新的BasicCalculator(),新的另一个计算器()
});
var WorkItem=新的WorkItem(
我
“测试任务”,
约会时间,现在
};
var result=handler.executealCalculators(WorkItem);
);
列表。添加(任务);
}
Task.WaitAll(列表);
}
}
这是系统的简化版本。实际系统有一系列计算器,计算器和计算器处理器通过IoC等注入

我的问题是-帮助我理解以下几点:

  • 每个任务都会创建CalculatorHandler的新实例和ICalculators的新实例。计算器不执行任何I/O操作,只创建一个新的私有IList。计算器处理程序和计算器实例现在是线程安全的吗

  • CalculatorHandler更新工作项但在锁中。锁是静态私有对象。这是否意味着CalculatorHandler的所有实例将共享一个锁,因此在某一点上,只有一个线程可以更新工作项

  • 工作项具有除CalculatedValues属性之外的所有公共getter属性。CalculatedValues仅在静态锁中设置。此代码现在是线程安全的吗

  • 1) 创建一个类的新实例,即使没有公共属性,也不能保证线程安全。问题是ExecuteAllCalculators接受两个对象参数。WorkItem对象包含可变属性,同一WorkItem对象用于所有ICalculator调用。假设其中一个计算器决定对WorkItem.CalculatedValues调用Clear()。或者假设一个计算器将WorkItem.Name设置为null,而下一个计算器决定执行WorkItem.Name.Length。从技术上讲,这不是一个“线程”问题,因为这些问题可以在没有多个线程参与的情况下发生

    2) 跨线程共享的计算器对象肯定不是线程安全的。假设其中一个计算器实例使用类级别变量。除非该变量以某种方式受到线程保护(例如:lock{…}),否则可能会产生不一致的结果。根据计算器实例的实现者的“创造性”程度,可能会出现死锁

    3) 每当代码接受接口时,您都在邀请人们“在您的沙箱中玩”。它允许执行您几乎无法控制的代码。处理此问题的最佳方法之一是使用不可变对象。不幸的是,在不破坏接口约定的情况下,无法更改WorkItem定义

    4) 计算器是通过引用传递的。代码显示_myCalculators在创建的所有任务中共享。这并不能保证你会有问题,它只会让你可能有问题

  • 不,它不是线程安全的。如果在任何计算中存在任何共享状态,则可能存在线程问题。避免线程问题的唯一方法是确保不更新任何共享状态。这意味着只读对象和/或使用

  • 您已经使用了“共享”一词——这意味着由于共享状态而不具有线程安全性。除非你的意思是“分布式”而不是“共享”

  • 独占使用只读对象

  • 它们是引用类型,因此它们可以在单独的线程之间共享,因此不是线程安全的,除非它们是只读的

  • 以下是只读对象的示例:

    public sealed class WorkItem : IEquatable<WorkItem>
    {
        private readonly int _id;
        private readonly string _name;
        private readonly DateTime _dateCreated;
    
        public int Id { get { return _id; } }
        public string Name { get { return _name; } }
        public DateTime DateCreated { get { return _dateCreated; } }
    
        public WorkItem(int id, string name, DateTime dateCreated)
        {
            _id = id;
            _name = name;
            _dateCreated = dateCreated;
        }
    
        public override bool Equals(object obj)
        {
            if (obj is WorkItem)
                return Equals((WorkItem)obj);
            return false;
        }
    
        public bool Equals(WorkItem obj)
        {
            if (obj == null) return false;
            if (!EqualityComparer<int>.Default.Equals(_id, obj._id)) return false;
            if (!EqualityComparer<string>.Default.Equals(_name, obj._name)) return false;
            if (!EqualityComparer<DateTime>.Default.Equals(_dateCreated, obj._dateCreated)) return false;
            return true;
        }
    
        public override int GetHashCode()
        {
            int hash = 0;
            hash ^= EqualityComparer<int>.Default.GetHashCode(_id);
            hash ^= EqualityComparer<string>.Default.GetHashCode(_name);
            hash ^= EqualityComparer<DateTime>.Default.GetHashCode(_dateCreated);
            return hash;
        }
    
        public override string ToString()
        {
            return String.Format("{{ Id = {0}, Name = {1}, DateCreated = {2} }}", _id, _name, _dateCreated);
        }
    
        public static bool operator ==(WorkItem left, WorkItem right)
        {
            if (object.ReferenceEquals(left, null))
            {
                return object.ReferenceEquals(right, null);
            }
    
            return left.Equals(right);
        }
    
        public static bool operator !=(WorkItem left, WorkItem right)
        {
            return !(left == right);
        }
    }
    
    公共密封类工作项:IEquatable
    {
    私有只读int_id;
    私有只读字符串\u名称;
    私有只读日期时间_dateCreated;
    公共int-Id{get{return_-Id;}}
    公共字符串名称{get{return{U Name;}}
    public DateTime DateCreated{get{return\u DateCreated;}}
    公共工作项(int-id、字符串名、DateTime-dateCreated)
    {
    _id=id;
    _名称=名称;
    _dateCreated=dateCreated;
    }
    公共覆盖布尔等于(对象对象对象)
    {
    如果(对象是工作项)
    返回等于((工作项)obj);
    返回false;
    }
    公共布尔等于(工作项对象)
    {
    if(obj==null)返回false;
    如果(!EqualityComparer.Default.Equals(_id,obj._id))返回false;
    如果(!eq)
    
    public class Client
    {
        
        public void ExecuteCalculators()
        {
            var list = new List<Task>();
            for(int i =0; i <10;i++)
            {
                Task task = new Task(() => 
                    
                    //new handler instance and new calculator instances
                    var handler = new CalculatorHandler(new[]{
                      new BasicCalculator(), new AnotherCalculator()
                    });
                
                    var WorkItem = new WorkItem(
                        i,
                        "TestTask",
                        DateTime.Now
                    };
    
                    var result = handler.ExecuteAllCalculators(WorkItem);
                );
                list.Add(task);
            }
            
            Task.WaitAll(list);
        }
    }
    
    public sealed class WorkItem : IEquatable<WorkItem>
    {
        private readonly int _id;
        private readonly string _name;
        private readonly DateTime _dateCreated;
    
        public int Id { get { return _id; } }
        public string Name { get { return _name; } }
        public DateTime DateCreated { get { return _dateCreated; } }
    
        public WorkItem(int id, string name, DateTime dateCreated)
        {
            _id = id;
            _name = name;
            _dateCreated = dateCreated;
        }
    
        public override bool Equals(object obj)
        {
            if (obj is WorkItem)
                return Equals((WorkItem)obj);
            return false;
        }
    
        public bool Equals(WorkItem obj)
        {
            if (obj == null) return false;
            if (!EqualityComparer<int>.Default.Equals(_id, obj._id)) return false;
            if (!EqualityComparer<string>.Default.Equals(_name, obj._name)) return false;
            if (!EqualityComparer<DateTime>.Default.Equals(_dateCreated, obj._dateCreated)) return false;
            return true;
        }
    
        public override int GetHashCode()
        {
            int hash = 0;
            hash ^= EqualityComparer<int>.Default.GetHashCode(_id);
            hash ^= EqualityComparer<string>.Default.GetHashCode(_name);
            hash ^= EqualityComparer<DateTime>.Default.GetHashCode(_dateCreated);
            return hash;
        }
    
        public override string ToString()
        {
            return String.Format("{{ Id = {0}, Name = {1}, DateCreated = {2} }}", _id, _name, _dateCreated);
        }
    
        public static bool operator ==(WorkItem left, WorkItem right)
        {
            if (object.ReferenceEquals(left, null))
            {
                return object.ReferenceEquals(right, null);
            }
    
            return left.Equals(right);
        }
    
        public static bool operator !=(WorkItem left, WorkItem right)
        {
            return !(left == right);
        }
    }