2013-05-30 49 views
0

背景:防止嵌套建立使用互斥

我使用XNA,并有一个清单处理器,将整理所有资产在我的内容项目,通过这些分类(其中包括)其内置的类型。要做到这一点,我需要建立它们。其中一些资产具有自己使用清单的处理器,这意味着资产处理器试图调用清单处理器,所以我得到永无止境的递归。

问题:

我试图使用名为Mutex当项目打造的是递归来检测并抛出一个错误,这是其他地方处理,但它不能正常工作。

代码:正确使用Mutex类我

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent> 
{ 
    private static Mutex _LockingMutex = new Mutex(false, "ManifestProcessor"); 

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context) 
    { 
     // If we've already locked on this object then we're doing a build as a result of building some other asset, so throw an exception 
     if (!_LockingMutex.WaitOne(0)) 
     { 
      throw new NestedManifestBuildException(); 
     } 
     else 
     { 
      try 
      { 
       // Stuff that might cause this method to get 
       // invoked again (via reflection) 
      } 
      finally 
      { 
       _LockingMutex.ReleaseMutex(); 
      } 
     } 

是谁?如何检测递归调用Process

+0

什么样的情况下产生无尽的递归?如果可重用组件正在构建两次,则可以实现某种构建缓存并检查它。如果有某种循环引用,那么就需要对此进行检测。 – Romoku

+0

构建清单的过程的一部分需要构建所有其他资产。建立特定资产的过程需要建立清单。即他们互相呼叫。我意识到我有一个循环依赖意味着什么都不能建立,但我可以解决这个问题。我想检测递归,而不是在打开文件时采取IOException(这是我最初发现它的方式)。 –

+0

缓存应该肯定有帮助。您应该在管道中引入BuildStack以跟踪哪些资产正在构建中,这将解决您的递归问题。 – Romoku

回答

0

我会尝试实现一种方法来跟踪正在构建的内容以检测递归。由于Manifest可以聚合已经构建的资产,因此缓存还可以提高构建性能。研究使用Mediator Pattern将资产与清单分离。

样品:

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent> 
{ 
    private static readonly Dictionary<string, ContentManifestContent> BuildCache = new Dictionary<string, ContentManifestContent>(); 

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context) 
    { 
     ContentManifestContent content; 

     if(!BuildCache.TryGetValue(input.Name, out content)) 
     { 
      VerifyStackIntegrity(context, input.Name); 
      content = Build(input, context); 
      BuildCache.Add(input.Name, content); 
      context.BuildStack.Pop(); 
     } 

     return content; 
    } 

    private static void VerifyStackIntegrity(ContentProcessorContext context, string buildStep) 
    { 
     if(context.BuildStack.Count(x => x == buildStep) > 1) 
      throw new CircularBuildException(); 

     context.BuildStack.Push(buildStep); 
    } 

    private static ContentManifestContent Build(ContentManifestAsset input, ContentProcessorContext context) 
    { 
     // build steps for Manifest/Assets/Recursion 
    } 
} 

如果你想防止递归时期那么最简单的方法是添加一个标志。

public class ManifestProcessor : ContentProcessor<ContentManifestAsset, ContentManifestContent> 
{ 
    private static bool InProgress = false; 

    public override ContentManifestContent Process(ContentManifestAsset input, ContentProcessorContext context) 
    { 
     if(InProgress) throw new InProgressBuildException(); 

     InProgress = true; 

     return Build(input, context); 
    } 

    private static ContentManifestContent Build(ContentManifestAsset input, ContentProcessorContext context) 
    { 
     ContentManifestContent content; 
     // build steps for Manifest/Assets/Recursion 
     InProgress = false; 

     return content; 
    } 
} 
+0

这看起来很有趣,但可能会让我的需求过于复杂。有没有任何理由为什么我不会工作? –

+0

'Mutex'不会阻塞递归线程。它只会阻止单独的线程同时进入关键部分。 – Romoku

+0

如果不允许递归,另一种方法是使用简单的标志来指示方法已经在进行中。我会用一个例子编辑我的帖子。 – Romoku