双重检查锁定可能的错误实现

时间:2016-07-18 09:37:37

标签: c# multithreading

我有一个线程安全类:

internal class ExmplFile 
{
    private readonly string filename;
    private int resolution;
    private volatile PaddedImage gaussian;
    private object lockObject=new object();

    //blah, blah, blah

    internal PaddedImage Gaussian()
    {
        if (gaussian != null)
        {
            return gaussian;
        }
        lock (lockObject)
        {
            if (gaussian == null)
            {
                Image();
                if (File.Exists(filename + "-gaus.raw"))
                {
                    gaussian = LoadImage(filename + "-gaus.raw", TerraGodContext.Instance()
                        .Config.PpaCandidateRange);
                    gaussian.ConformRepeatPadding();
                }
                else
                {
                    gaussian = new PaddedImage(resolution, resolution, false, 
                        TerraGodContext.Instance().Config.PpaCandidateRange);
                    PaddedImage temp = new PaddedImage(resolution, resolution, false, 
                        TerraGodContext.Instance().Config.PpaCandidateRange);
                    ImageProcessing.CalcGaussian(image,gaussian,temp, 16f* resolution
                        /TerraGodContext.Instance().Config.ExmplResDS);
                }
            }
        }
        return gaussian;
    }

}

Resharper给了我三个警告:

  1. gaussian.ConformRepeatPadding()的高斯上,它表示 可能错误地实现了双重检查锁定。对已检查字段的读访问权。
  2. gaussian = new PaddedImage(的高斯上,它表示 可能错误地实现了双重检查锁定。可能对已检查字段进行多次写访问。
  3. ImageProcessing.CalcGaussian(image,gaussian,temp,的高斯上,它表示 可能错误地实现了双重检查锁定。读取对已检查字段的访问权限。 (与编号1相同的警告)。
  4. 我是傻还是Resharper?

    PS:如果我错过了一些重要内容,这里是完整的类代码,上面省略了部分内容。

    using System;
    using System.IO;
    using System.Text;
    
    namespace UPlus.TerrEngine
    {
    internal class ExmplFile : IEquatable<ExmplFile>
    {
        private readonly string filename;
        private int resolution;
        private volatile PaddedImage image;
        private volatile PaddedImage gaussian;
        private object lockObject=new object();
        public ExmplFile(string abstractFileName, int res)
        {
            filename = new StringBuilder(abstractFileName).Append("-").Append(res.ToString("D4")).ToString();
            resolution = res;
        }
    
        internal FilledList<MatchItem>[] GetMatchItems(int groupIdx, int regionIdx)
        {
            AlgorithmConfig Config = TerraGodContext.Instance().Config;
            if (resolution !=Config.ExmplResDS) throw new Exception();
            PpaGraph exmplGraph = new PpaGraph(Config.ExmplResDS, Config.ExmplResDS, Config.ExmplResDS
                / Config.PpaExmplResDS);
            exmplGraph.Calculate(Image(), true, false, DebugOpts.BranchMin);
            exmplGraph.PrepareGraphForMatch(Config.ExmplCptRadius, Config.ExmplProcNodeDistance);
            exmplGraph.CalcExmplProcNodeGroups(groupIdx);
            MatchItemFinder matchItemFinder=new MatchItemFinder(Image(),Config.ExmplPatchSizeDS,true);
            matchItemFinder.Init(exmplGraph.processNodesGroups, regionIdx);
            return matchItemFinder.matchItems;
        }
    
        internal FastList<MatchItem> LoadMatchItems()
        {
            throw new Exception();
        }
    
        internal PaddedImage Image()
        {
            if (image != null)
            {
                return image;
            }
            lock (lockObject)
            {
                if (image == null)
                {
                    image=LoadImage(filename + ".raw", TerraGodContext.Instance().Config
                        .PpaCandidateRange);
                }
            }
            return image;
        }
        internal PaddedImage Gaussian()
        {
            if (gaussian != null)
            {
                return gaussian;
            }
            lock (lockObject)
            {
                if (gaussian == null)
                {
                    Image();
                    if (File.Exists(filename + "-gaus.raw"))
                    {
                        gaussian = LoadImage(filename + "-gaus.raw", TerraGodContext.Instance()
                            .Config.PpaCandidateRange);
                        gaussian.ConformRepeatPadding();
                    }
                    else
                    {
                        gaussian = new PaddedImage(resolution, resolution, false, 
                            TerraGodContext.Instance().Config.PpaCandidateRange);
                        PaddedImage temp = new PaddedImage(resolution, resolution, false, 
                            TerraGodContext.Instance().Config.PpaCandidateRange);
                        ImageProcessing.CalcGaussian(image,gaussian,temp, 16f* resolution
                            /TerraGodContext.Instance().Config.ExmplResDS);
                    }
                }
            }
            return gaussian;
        }
    
        private PaddedImage LoadImage(string fileName, int padding)
        {
            PaddedImage img=new PaddedImage(resolution,resolution,false,padding);
            img.LoadRaw(fileName);
            img.ConformRepeatPadding();
            return img;
        }
    
        public bool Equals(ExmplFile other)
        {
            return filename == other.filename;
        }
    
        public override int GetHashCode()
        {
            return filename.GetHashCode();
        }
      }
    }
    

    编辑:以下是情况不明确的截图:

    enter image description here

3 个答案:

答案 0 :(得分:2)

尝试使用Lazy<T>来定义您的媒体资源。你的代码看起来是正确的,但这应该摆脱错误,并且是一种框架模式,正是这种事情

答案 1 :(得分:2)

通常,在lock内,您应该使用局部变量并对已检查字段进行 last 可能的操作。

否则,你在中间做什么?例如。 ConformRepeatPadding()做了什么?我猜它有副作用,因为它没有返回值?但是当你调用它时,你已经已经通过将该值赋给该字段来公开该对象。

如果您过早地分配给该字段,其他线程可能能够以“部分构造”状态观察此对象,因此我应该通常在{{{{{{{{{ 1}}。

答案 2 :(得分:0)

你的锁有些奇怪。我已经在静态锁定对象上看到了它,而不是私有对象。 如果你的班级不是单身,那么你的锁定就会通过,因为没有锁定。