我有一个线程安全类:
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 给我三个警告:
- 在
gaussian.ConformRepeatPadding()中的 gaussian 上它说 双重检查锁定的可能不正确的实现。读取选中字段的权限。。 - 在
gaussian = new PaddedImage(中的 gaussian 上,它说 双重检查锁定的可能不正确的实现。可能对检查的字段进行多次写入访问。. - 在
ImageProcessing.CalcGaussian(image,gaussian,temp,中的 gaussian 上显示双重检查锁定的可能不正确的实现。读取检查字段的权限。 (与第 1 条警告相同)。
是我傻还是 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();
}
}
}
编辑:以下是截图以防情况不清楚:
请您参考如下方法:
一般来说,在 lock 内,您应该使用局部变量并将写入选中的字段作为最后可能的操作。
不然你在中间对它做什么?例如。 ConformRepeatPadding() 是做什么的?我猜它有副作用,因为它没有返回值?但是当您调用它时,您已经通过将它的值分配给该字段来公开该对象。
如果您过早地分配给该字段,其他线程可能会在“部分构造”状态下观察到该对象,因此正如我所说,您通常应该将写入该字段作为 lock 中最后可能的操作。
