如何使用lock语句避免null?

问题描述 投票:0回答:2

我有一个方法,将并行加载并运行报表布局。所有报告都将使用相同的baselayout.xml。由于线程每次尝试访问同一资源时都会因异常而失败,因此我使用lock来锁定文件。

public static XmlTextReader LoadReport(string reportName)
{
    object _locker = new object();
    object reportData;
    lock (_locker)
    {
        reportData = Resources.ResourceManager.GetObject(reportName);
    }
    return new XmlTextReader(new MemoryStream((byte[])reportData));
}

并行方法如下所示:

private void RunReportsParallel(List<ReportObject> coverterList)
{
    try
    {
        Parallel.ForEach(coverterList, (currentObject) => {
            currentObject.Convert();
        });    
    }
    catch (Exception e)
    {
        smlLogger.Error(Helper.SetLogLine(e.Message, processId));
        throw;
    }
}

转换将运行以下代码:

public override SectionReport GetMainReport()
{
    SectionReport mainReport = new SectionReport();
    XMLDataSource datasource = new XMLDataSource(null, "//AkontoRechnung");
    datasource.LoadXML(rechnungsdaten.ToString());
    mainReport = new ReportAkontorechnung(datasource, reportConfiguration, Language, NoPrintOut);
    try
    {
        mainReport.Run();
    }
    catch (Exception e)
    {
        smlLogger.Error(Helper.SetLogLine(string.Format("Error creating Report: {0}", e.Message), processId));
        throw;
    }
    return mainReport;
}

ReportAkontorechnung.cs中抛出错误的行:

this.LoadLayout(Helper.LoadReport("ReportAkontoZusammenfassung"));最后,错误:

bei GrapeCity.ActiveReports.Controls.Image.Load(Stream stream, Boolean checkMagic)
bei GrapeCity.ActiveReports.SectionReport.#Pyb(XmlNode node)
bei GrapeCity.ActiveReports.SectionReport.#Qyb(XmlDocument layoutDoc, Boolean checkNames)
bei GrapeCity.ActiveReports.SectionReport.LoadLayout(XmlReader reader, ArrayList& errors)
bei GrapeCity.ActiveReports.SectionReport.LoadLayout(XmlReader reader)   
bei GFPrinting.Domain.ReportAkontorechnung.InitializeReport() 
     in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\ReportAkontorechnung.cs:Zeile 108.
bei GFPrinting.Domain.ReportAkontorechnung..ctor(XMLDataSource reportNavigation, ReportConfiguration reportConfiguration, String reportLanguage, Boolean noPrintout) 
     in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\ReportAkontorechnung.cs:Zeile 79.
bei GFPrinting.Domain.Akontorechnung.GetMainReport() 
    in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\Akontorechnung.cs:Zeile 42.
bei GFPrinting.Domain.Change.ReportObject.Convert() 
    in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\ReportObject.cs:Zeile 33.
bei GFPrinting.Domain.Rechnungshandler.<>c.<RunReportsParallel>b__13_0(ReportObject currentObject) 
    in C:\Dev\GFPrinting\Ruf.GFPrinting\branch\Concurrent\trunc\Source\SMLPrinting\Domain\Change\Rechnungshandler.cs:Zeile 103.
bei System.Threading.Tasks.Parallel.<>c__DisplayClass31_0`2.<ForEachWorker>b__0(Int32 i)
bei System.Threading.Tasks.Parallel.<>c__DisplayClass17_0`1.<ForWorker>b__1()
bei System.Threading.Tasks.Task.InnerInvoke()
bei System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
bei System.Threading.Tasks.Task.<>c__DisplayClass176_0.<ExecuteSelfReplicating>b__0(Object)

信息:

内部异常1:NullReferenceException:对象引用未设置为对象实例。对象引用未设置为对象实例。 (对象引用不指向对象实例。)

如何解决返回null的问题? 编辑: 利亚姆的评论似乎解决了大多数问题。不使用并行加载,而是并行运行。我是在注意错误看到这样的选择。

c# multithreading xmlreader parallel.foreach activereports
2个回答
5
投票

您正在获取本地对象的锁定!将_locker声明为类中的私有静态对象(如果需要在实例中使用lock,请不要使用static。但是如果需要使用lock来处理此类的所有实例,则使用static。)

private static readonly object _locker = new object(); //readonly to avoid reassignment. static to lock on all instances.

然后把_locker锁定为

lock(_locker)
{

}

虽然可以有办法进行无锁并行报告。


0
投票

有点PLINQ,这将是非常严格的。从名称开始,按顺序将它们映射到资源,然后将资源并行映射到其处理的输出。

可能看起来有点像这样:

const string[] reportNames = { "ReportA", "ReportB" };
var results = reportNames
    .AsSequential()
    .Select
    (
        name => Resources.ResourceManager.GetObject(name)
    )
    .AsParallel()
    .Select
    ( 
        reportData => DoSomethingCpuBound
        (
            new XmlTextReader(new MemoryStream((byte[])reportData))
        )
    )
    .ToList();

这样,资源将按顺序加载,但处理并行进行。此外,此解决方案完全避免任何线程问题,因此不需要任何锁定。

注意:AsSequential()调用并不是真正需要的(顺序是默认值),但我把它放在那里是为了说明目的。

© www.soinside.com 2019 - 2024. All rights reserved.