如何避免用lock语句返回null?

时间:2019-04-05 07:06:20

标签: c# multithreading xmlreader parallel.foreach activereports

我有一个方法可以并行加载并运行报表布局。所有报告将使用相同的games。由于线程每次尝试访问同一资源时都会因异常而失败,因此我使用了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));
}

Conver将运行以下代码:

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"));
  

消息:

     

内部异常1:NullReferenceException:Der Objektverweis wurde    可以在Obestktinstanz电影节上观看。民主运动    奥布涅克斯坦斯坦节日音乐节。    (对象引用未指向对象实例。)

如何解决返回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) 的问题?

编辑
利亚姆的言论似乎可以解决大多数问题。不使用并行加载,而是并行运行。我本来想知道看到这种选择的错误。

2 个答案:

答案 0 :(得分:5)

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

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

然后以{p> 1的身份锁定

_locker

尽管可以有一些方法来进行无锁并行报告。

答案 1 :(得分: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()调用(默认是顺序调用),但出于说明目的,我将其放在此处。