使用Mutex防止嵌套构建

时间:2013-05-30 12:02:36

标签: c# multithreading recursion xna mutex

背景:

我正在使用XNA并拥有一个清单处理器,它将整理我的内容项目中的所有资产,并根据(除其他事项)对其构建类型进行分类。要做到这一点,我需要建立它们。其中一些资产有一个处理器本身使用清单,这意味着资产处理器试图调用清单处理器,所以我得到永无止境的递归。

问题:

我尝试使用一个名为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();
            }
        }

我是否正确使用Mutex类?如何检测递归调用Process

1 个答案:

答案 0 :(得分: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;
    }
}