C# XNA Xbox 360内容管理器线程冻结绘制线程

C# XNA Xbox 360内容管理器线程冻结绘制线程,c#,multithreading,xna,file-management,C#,Multithreading,Xna,File Management,我目前有一款游戏,它可以拍摄大图像,很容易超过1MB,作为背景。我确切地知道这个转换应该在什么时候发生,所以我创建了一个loader类来处理在背景中加载这些大图像,但是当我加载这些图像时,它仍然冻结了发生绘图的主线程。由于该代码在360上运行,我将线程移动到第四个硬件线程,但这似乎没有帮助。下面是我正在使用的类。对于我的新内容管理器(应该在自己的线程中)为什么会中断我主线程中的绘图,如果您有任何想法,我们将不胜感激 namespace FileSystem { /// <summary

我目前有一款游戏,它可以拍摄大图像,很容易超过1MB,作为背景。我确切地知道这个转换应该在什么时候发生,所以我创建了一个loader类来处理在背景中加载这些大图像,但是当我加载这些图像时,它仍然冻结了发生绘图的主线程。由于该代码在360上运行,我将线程移动到第四个硬件线程,但这似乎没有帮助。下面是我正在使用的类。对于我的新内容管理器(应该在自己的线程中)为什么会中断我主线程中的绘图,如果您有任何想法,我们将不胜感激

namespace FileSystem  
{
/// <summary>
/// This is used to reference how many objects reference this texture.
/// Everytime someone references a texture we increase the iNumberOfReferences.
/// When a class calls remove on a specific texture we check to see if anything
/// else is referencing the class, if it is we don't remove it. If there isn't 
/// anything referencing the texture its safe to dispose of.
/// </summary>
class TextureContainer
{
    public uint uiNumberOfReferences = 0;
    public Texture2D texture;
}

/// <summary>
/// This class loads all the files from the Content.
/// </summary>
static class FileManager
{
    static Microsoft.Xna.Framework.Content.ContentManager Content; 
    static EventWaitHandle wh = new AutoResetEvent(false);
    static Dictionary<string, TextureContainer> Texture2DResourceDictionary;
    static List<Texture2D> TexturesToDispose;
    static List<String> TexturesToLoad;
    static int iProcessor = 4;

    private static object threadMutex = new object();
    private static object Texture2DMutex = new object();
    private static object loadingMutex = new object();

    private static bool bLoadingTextures = false;

    /// <summary>
    /// Returns if we are loading textures or not.
    /// </summary>
    public static bool LoadingTexture
    {
        get {
                lock (loadingMutex)
                {
                    return bLoadingTextures;
                }
            }
    }

    /// <summary>
    /// Since this is an static class. This is the constructor for the file loadeder. This is the version
    /// for the Xbox 360.
    /// </summary>
    /// <param name="_Content"></param>
    public static void Initalize(IServiceProvider serviceProvider, string rootDirectory, int _iProcessor )
    {
        Content = new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider, rootDirectory);
        Texture2DResourceDictionary = new Dictionary<string, TextureContainer>();
        TexturesToDispose = new List<Texture2D>();
        iProcessor = _iProcessor;
        CreateThread();
    }

    /// <summary>
    /// Since this is an static class. This is the constructor for the file loadeder.
    /// </summary>
    /// <param name="_Content"></param>
    public static void Initalize(IServiceProvider serviceProvider, string rootDirectory)
    {
        Content = new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider, rootDirectory);
        Texture2DResourceDictionary = new Dictionary<string, TextureContainer>();
        TexturesToDispose = new List<Texture2D>();
        CreateThread();
    }

    /// <summary>
    /// Creates the thread incase we wanted to set up some parameters
    /// Outside of the constructor.
    /// </summary>
    static public void CreateThread()
    {
        Thread t = new Thread(new ThreadStart(StartThread));
        t.Start();

    }

    // This is the function that we thread.
    static public void StartThread()
    {
        //BBSThreadClass BBSTC = (BBSThreadClass)_oData;
        FileManager.Execute();
    }

    /// <summary>
    /// This thread shouldn't be called by the outside world.
    /// It allows the File Manager to loop.
    /// </summary>
    static private void Execute()
    {
        // Make sure our thread is on the correct processor on the XBox 360.
#if WINDOWS 
#else
        Thread.CurrentThread.SetProcessorAffinity(new int[] { iProcessor });
        Thread.CurrentThread.IsBackground = true;
#endif
        // This loop will load textures into ram for us away from the main thread.
        while (true)
        {
            wh.WaitOne();
            // Locking down our data while we process it.
            lock (threadMutex)
            {
                lock (loadingMutex)
                {
                    bLoadingTextures = true;
                }
                bool bContainsKey = false;
                for (int con = 0; con < TexturesToLoad.Count; con++)
                {
                    // If we have already loaded the texture into memory reference
                    // the one in the dictionary.
                    lock (Texture2DMutex)
                    {
                        bContainsKey = Texture2DResourceDictionary.ContainsKey(TexturesToLoad[con]);
                    }

                    if (bContainsKey)
                    {
                        // Do nothing
                    }
                    // Otherwise load it into the dictionary and then reference the
                    // copy in the dictionary
                    else
                    {
                        TextureContainer TC = new TextureContainer();
                        TC.uiNumberOfReferences = 1;    // We start out with 1 referece.
                        // Loading the texture into memory.

                        try
                        {
                            TC.texture = Content.Load<Texture2D>(TexturesToLoad[con]);

                            // This is passed into the dictionary, thus there is only one copy of
                            // the texture in memory.

                            // There is an issue with Sprite Batch and disposing textures.
                            // This will have to wait until its figured out.
                            lock (Texture2DMutex)
                            {
                                bContainsKey = Texture2DResourceDictionary.ContainsKey(TexturesToLoad[con]);
                                Texture2DResourceDictionary.Add(TexturesToLoad[con], TC);
                            }
                            // We don't have the find the reference to the container since we
                            // already have it.
                        }
                        // Occasionally our texture will already by loaded by another thread while 
                        // this thread is operating. This mainly happens on the first level.
                        catch (Exception e)
                        {
                            // If this happens we don't worry about it since this thread only loads
                            // texture data and if its already there we don't need to load it.
                        }
                    }
                    Thread.Sleep(100);
                }
            }
            lock (loadingMutex)
            {
                bLoadingTextures = false;
            }
        }
    }

    static public void LoadTextureList(List<string> _textureList)
    {
        // Ensuring that we can't creating threading problems.
        lock (threadMutex)
        {
            TexturesToLoad = _textureList;
        }
        wh.Set();
    }

    /// <summary>
    /// This loads a 2D texture which represents a 2D grid of Texels.
    /// </summary>
    /// <param name="_textureName">The name of the picture you wish to load.</param>
    /// <returns>Holds the image data.</returns>
    public static Texture2D LoadTexture2D( string _textureName )
    {
        TextureContainer temp;
        lock (Texture2DMutex)
        {
            bool bContainsKey = false;
            // If we have already loaded the texture into memory reference
            // the one in the dictionary.
            lock (Texture2DMutex)
            {
                bContainsKey = Texture2DResourceDictionary.ContainsKey(_textureName);

                if (bContainsKey)
                {
                    temp = Texture2DResourceDictionary[_textureName];
                    temp.uiNumberOfReferences++;    // Incrementing the number of references
                }
                // Otherwise load it into the dictionary and then reference the
                // copy in the dictionary
                else
                {
                    TextureContainer TC = new TextureContainer();
                    TC.uiNumberOfReferences = 1;    // We start out with 1 referece.
                    // Loading the texture into memory.
                    try
                    {
                        TC.texture = Content.Load<Texture2D>(_textureName);

                        // This is passed into the dictionary, thus there is only one copy of
                        // the texture in memory.
                    }
                    // Occasionally our texture will already by loaded by another thread while 
                    // this thread is operating. This mainly happens on the first level.
                    catch(Exception e)
                    {
                        temp = Texture2DResourceDictionary[_textureName];
                        temp.uiNumberOfReferences++;    // Incrementing the number of references
                    }

                    // There is an issue with Sprite Batch and disposing textures.
                    // This will have to wait until its figured out.
                    Texture2DResourceDictionary.Add(_textureName, TC);

                    // We don't have the find the reference to the container since we
                    // already have it.
                    temp = TC;
                }
            }
        }
        // Return a reference to the texture
        return temp.texture;
    }

    /// <summary>
    /// Go through our dictionary and remove any references to the
    /// texture passed in.
    /// </summary>
    /// <param name="texture">Texture to remove from texture dictionary.</param>
    public static void RemoveTexture2D(Texture2D texture)
    {
        foreach (KeyValuePair<string, TextureContainer> pair in Texture2DResourceDictionary)
        {
            // Do our references match?
            if (pair.Value.texture == texture)
            {
                // Only one object or less holds a reference to the 
                // texture. Logically it should be safe to remove.
                if (pair.Value.uiNumberOfReferences <= 1)
                {
                    // Grabing referenc to texture
                    TexturesToDispose.Add(pair.Value.texture);
                    // We are about to release the memory of the texture,
                    // thus we make sure no one else can call this member
                    // in the dictionary.
                    Texture2DResourceDictionary.Remove(pair.Key);
                    // Once we have removed the texture we don't want to create an exception.
                    // So we will stop looking in the list since it has changed.
                    break;
                }
                // More than one Object has a reference to this texture.
                // So we will not be removing it from memory and instead 
                // simply marking down the number of references by 1.
                else
                {
                    pair.Value.uiNumberOfReferences--;
                }
            }
        }
    }

    /*public static void DisposeTextures()
    {
        int Count = TexturesToDispose.Count;
        // If there are any textures to dispose of.
        if (Count > 0)
        {
            for (int con = 0; con < TexturesToDispose.Count; con++)
            {
                // =!THIS REMOVES THE TEXTURE FROM MEMORY!=
                // This is not like a normal dispose. This will actually
                // remove the object from memory. Texture2D is inherited
                // from GraphicsResource which removes it self from 
                // memory on dispose. Very nice for game efficency,
                // but "dangerous" in managed land.
                Texture2D Temp = TexturesToDispose[con];
                Temp.Dispose();
            }
            // Remove textures we've already disposed of.
            TexturesToDispose.Clear();
        }
    }*/

    /// <summary>
    /// This loads a 2D texture which represnets a font.
    /// </summary>
    /// <param name="_textureName">The name of the font you wish to load.</param>
    /// <returns>Holds the font data.</returns>
    public static SpriteFont LoadFont( string _fontName )
    {
        SpriteFont temp = Content.Load<SpriteFont>( _fontName );
        return temp;
    }

    /// <summary>
    /// This loads an XML document.
    /// </summary>
    /// <param name="_textureName">The name of the XML document you wish to load.</param>
    /// <returns>Holds the XML data.</returns>
    public static XmlDocument LoadXML( string _fileName )
    {
        XmlDocument temp = Content.Load<XmlDocument>( _fileName );
        return temp;
    }

    /// <summary>
    /// This loads a sound file.
    /// </summary>
    /// <param name="_fileName"></param>
    /// <returns></returns>
    public static SoundEffect LoadSound( string _fileName )
    {
        SoundEffect temp = Content.Load<SoundEffect>(_fileName);
        return temp;
    }
}
}
命名空间文件系统
{
/// 
///这用于参考有多少对象引用此纹理。
///每次有人引用纹理时,我们都会增加iNumberOfReferences。
///当一个类调用特定纹理上的remove时,我们会检查是否有任何内容
///else正在引用该类,如果是,我们不删除它。如果没有
///任何引用纹理的内容都可以安全地处理。
/// 
类TextureContainer
{
公共uint uiNumberOfReferences=0;
公共纹理2D纹理;
}
/// 
///此类加载内容中的所有文件。
/// 
静态类文件管理器
{
静态Microsoft.Xna.Framework.Content.ContentManager内容;
静态EventWaitHandle wh=新的自动重置事件(false);
静态字典;数据源字典;
静态列表处理;
静态列表加载;
静态int iProcessor=4;
私有静态对象threadMutex=新对象();
私有静态对象Texture2DMutex=新对象();
私有静态对象loadingMutex=新对象();
私有静态bool bLoadingTextures=false;
/// 
///返回是否加载纹理。
/// 
公共静态bool加载文本
{
得到{
锁(加载互斥)
{
返回bLoadingTextures;
}
}
}
/// 
///因为这是一个静态类。这是文件Loader的构造函数。这是版本
///对于Xbox360。
/// 
/// 
公共静态void Initalize(IServiceProvider服务提供程序、字符串根目录、int\u IPProcessor)
{
Content=new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider,rootDirectory);
Texture2DResourceDictionary=新字典();
TexturesToDispose=新列表();
i处理器=_i处理器;
CreateThread();
}
/// 
///因为这是一个静态类。这是文件Loader的构造函数。
/// 
/// 
公共静态void初始化(IServiceProvider服务提供程序,字符串根目录)
{
Content=new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider,rootDirectory);
Texture2DResourceDictionary=新字典();
TexturesToDispose=新列表();
CreateThread();
}
/// 
///创建线程,以防我们要设置一些参数
///在构造函数之外。
/// 
静态公共void CreateThread()
{
线程t=新线程(新线程开始(StartThread));
t、 Start();
}
//这是我们线程的函数。
静态公共void StartThread()
{
//BBSThreadClass BBSTC=(BBSThreadClass)\u oData;
Execute();
}
/// 
///这个线程不应该被外部世界调用。
///它允许文件管理器循环。
/// 
静态私有void Execute()
{
//确保我们的线程位于XBox 360上的正确处理器上。
#如果窗口
#否则
Thread.CurrentThread.SetProcessorAffinity(新的int[]{IPProcessor});
Thread.CurrentThread.IsBackground=true;
#恩迪夫
//这个循环将把纹理从主线程加载到ram中。
while(true)
{
wh.WaitOne();
//在处理数据时锁定数据。
锁(线程互斥)
{
锁(加载互斥)
{
bLoadingTextures=true;
}
bool bContainsKey=false;
对于(int con=0;con