Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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# 流式API周围的锁定和线程安全_C#_.net_Multithreading_Locking_Ienumerable - Fatal编程技术网

C# 流式API周围的锁定和线程安全

C# 流式API周围的锁定和线程安全,c#,.net,multithreading,locking,ienumerable,C#,.net,Multithreading,Locking,Ienumerable,可能是一个相当简单的问题,但我想知道使代码线程安全的最佳实践 我在多线程环境中使用外部非线程安全API 它返回一个IEnumerable。 然后,我将每个ApiDto映射到应用程序的DTO:MyDto 如何确保代码是线程安全的 例如: 这是我从API获取项目的类 public class ApiRepo { private IApi api; public ApiRepo() { api=new Api("url"); } public I

可能是一个相当简单的问题,但我想知道使代码线程安全的最佳实践

我在多线程环境中使用外部非线程安全API

它返回一个IEnumerable。 然后,我将每个ApiDto映射到应用程序的DTO:MyDto

如何确保代码是线程安全的

例如:

这是我从API获取项目的类

public class ApiRepo
{
    private IApi api;
    public ApiRepo()
    {
        api=new Api("url");
    }
    public IEnumerable<MyDto> GetItems()
    {
        var apiDtos = api.GetNonThreadSafeItems();
        foreach(var apiDto in apiDtos)
        {
           var myDto = new MyDto(apiDto.Name);  
           yield return myDto;
        }

    }

}

我应该在Client.GetData中设置锁,还是有更好的方法使代码线程安全?

API是“非线程安全”的,这意味着它在没有同步机制的情况下基于某些golbal资源运行。因此,为了从API中获得正确的结果,您需要确保一次只有一个线程调用它。根据您的样本,最简单的方法是

public class ApiRepo
{
    static private object theLock = new object();
    private IApi api;

    public ApiRepo()
    {
        api=new Api("url");
    }

    public IEnumerable<MyDto> GetItems()
    {
        IEnumerable<ApiDto> apiDtos = null;
        lock(theLock)
        {
            apiDtos = api.GetNonThreadSafeItems();
        }
        foreach(var apiDto in apiDtos)
        {
           var myDto = new MyDto(apiDto.Name);  
           yield return myDto;
        }
    }
}

它是一个第三方库,在文档中,它说这个Api不是线程安全的。对象被记录为不安全的。除非有关于如何使其安全的文档,否则您不知道如何使其安全。有些对象根本无法安全地在多个线程上运行。例如,考虑使用线程安全方式使用非线程安全对象的两种常见方法。单元系统是:创建任意数量的对象实例,但只在创建对象的线程上调用对象的方法。并不是每件物品都能安全穿线。租用系统是:创建任意多个对象实例,但进行安排,以便每次只有一个线程访问单个对象。并不是每件物品都可以安全使用。你必须知道物体的细节!例如,考虑一个对象,该对象包含对另一个同类对象的引用,并尝试通过锁保护对象。对象Foo和Bar都引用对象Blah。您通过锁安排Foo只在一个线程中使用,Bar只在一个线程中使用,但是没有任何东西可以阻止Foo和Bar在两个不同的线程上访问Blah,现在您是不安全的。您必须知道该类的所有实现细节,并且它们永远不能更改,以便知道您的锁是正确的!这就是为什么用锁编程很难。你应该相信文档。该对象不是线程安全的。所以不要从多个线程使用它。这里的建议是使用一个全局锁来获取对象的集合,但是假设对象本身不是线程安全的,而不仅仅是获取它们的API。所以这段代码不是线程安全的,因为它使用了全局锁,所以在争用场景中性能很差。此外,我们不知道被锁定的对象对于这种并发是安全的。您已经确保通过该类访问的每个Api实例都是在锁下访问的,但因此有可能在两个不同的时间在两个不同的线程上访问同一对象。这是出租线程模型,但假设底层对象仅是公寓线程安全的;然后呢?对象在使用时可能会崩溃,事实上,许多公寓线程对象在这种情况下故意崩溃。@EricLippert基于这个问题和示例代码,很难相信这篇文章的所有者想要在一个lock语句中保护所有东西。而且,线程安全只关注共享资源访问的竞争条件。如果一个类或库使用单线程单元模型来避免竞争条件,这只意味着属于库的类或类不能从多线程环境中访问,文档必须提到它,而不仅仅是说它们不是线程安全的。无论如何,不使用来自多线程的api仅仅因为它不是线程安全的对我来说是不明智的。
public class ApiRepo
{
    static private object theLock = new object();
    private IApi api;

    public ApiRepo()
    {
        api=new Api("url");
    }

    public IEnumerable<MyDto> GetItems()
    {
        IEnumerable<ApiDto> apiDtos = null;
        lock(theLock)
        {
            apiDtos = api.GetNonThreadSafeItems();
        }
        foreach(var apiDto in apiDtos)
        {
           var myDto = new MyDto(apiDto.Name);  
           yield return myDto;
        }
    }
}