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