【发布时间】:2013-08-11 23:40:45
【问题描述】:
我正在尝试创建一个媒体播放器(使用 Media.MediaPlayer() 类),为此我使用线程来处理用户使用 OpenFileDialog 加载的歌曲。我正在使用下一个代码来启动歌曲的处理过程:
public static List<MediaFile> MediaList = new List<MediaFile>();
public static Queue<String> MediaFilesQueue = new Queue<String>();
public static void AddMediaFilesToMediaList()
{
String pathToFile;
while (MediaFilesQueue.Count > 0)
// all the files are loaded into the Queue before processing
{
pathToFile = MediaFilesQueue.Dequeue();
MediaData.MediaList.Add(new MediaFile(pathToFile));
MediaFileCreator mfCreator =
new MediaFileCreator(MediaData.MediaList.Count - 1);
mfCreator.CreateNewMediaFile();
}
}
这是 MediaFileCreator 类:
public class MediaFileCreator
{
private int IndexOfMediaFileCurrentlyProcessed;
public MediaFileCreator(int idx)
{
IndexOfMediaFileCurrentlyProcessed = idx;
}
public void CreateNewMediaFile()
{
var indexOfMediaFileCurrentlyProcessed = IndexOfMediaFileCurrentlyProcessed;
var tempMediaFile = MediaData.MediaList[indexOfMediaFileCurrentlyProcessed];
var tempMediaPlayer = new MediaPlayer();
var waitHandle = new AutoResetEvent(false);
//EventHandler eventHandler = delegate(object sender, EventArgs args)
//{
// waitHandle.Set();
//};
tempMediaPlayer.MediaOpened += (sender, args) => waitHandle.Set();
tempMediaPlayer.Open(new Uri(tempMediaFile.PathToFile));
waitHandle.WaitOne();
//while (!tempMediaPlayer.NaturalDuration.HasTimeSpan)
//{
// Thread.Sleep(100);
//}
var tempTimeSpan = tempMediaPlayer.NaturalDuration.TimeSpan;
var hasVideo = tempMediaPlayer.HasVideo;
var hasAudio = tempMediaPlayer.HasAudio;
MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].HasVideo = hasVideo;
MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].HasAudio = hasAudio;
MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].TimeSpanOfMediaFile
= tempTimeSpan;
}
这是 MediaFile 类:
public class MediaFile
{
public bool HasAudio = false;
public bool HasVideo = false;
public TimeSpan TimeSpanOfMediaFile;
public String PathToFile = null;
public MediaFile(String pathToFile)
{
PathToFile = pathToFile;
}
}
我的问题是程序停在waitHandle.WaitOne(); 并尝试一次又一次地运行该行。我通过将该事件处理程序附加到 Open 事件来尝试其他变体,例如第一个注释部分中的变体,但结果是相同的:waitHandle.Set(); 从不执行,并且 waitHandle 的值始终为 false。我设法开始工作的唯一选择是第二个评论部分的解决方案:阻塞线程(使用 Thread.Sleep)直到文件完全加载(例如在初始化 TimeSpan 时加载文件)......这是我的应用程序的时间损失和性能下降。问题显然不在于事件本身,因为如果它在主线程上运行,事件就会触发(从 BackgroundWorker 线程调用 AddMediaFilesToMediaList() 方法,当它检测到有元素时在新线程中启动该方法队列; AddMediaFilesToMediaList() 线程是用 new Thread() 创建的,显然文件正在加载,因为 TimeSpan 已初始化。我真的很想让应用程序使用 waitHandle 或类似的东西工作。我不想使用 Thread.Sleep() 因为它很丑,而且当我尝试加载大量文件时我的应用程序也存在内存泄漏(我占用了 1.2 GB 的内存并且它因错误而停止(OutOfMemory) - 我尝试在其中加载 2048 首歌曲),我相信这可能是因为 Thread.Sleep()。即使不是,调试起来也会容易得多,而不会出现 Thread.Sleep() 的问题。
那么我怎样才能让 waitHandle 工作呢?我怎样才能让waitHandle.Set(); 运行?如果有人知道过多的内存使用可能来自哪里,那就太好了! (我个人认为这是 Thread.Sleep() 的错,但我不知道如何摆脱它)。
编辑:我使用 MediaFileCreator 对象的原因是最初我想使用 2 到 4 个线程的线程池来处理媒体文件,但我遇到了同样的问题,所以我删除了 ThreadPool 并尝试使用代码上面贴了,但同样的问题发生了。
编辑:我设法让它使用第二个线程来等待事件(现在不是最干净的代码,但我会做对的)。
public class MediaFileCreator
{
private AutoResetEvent openedEvent = new AutoResetEvent(false);
public MediaFile CreateNewMediaFile(string filename)
{
var mFile = new MediaFile(filename);
var thread = new Thread(WaitForEvent);
const int maxTimeToWait = 2000;
openedEvent.Reset();
thread.Start(mFile);
var mediaPlayer = new MediaPlayer();
mediaPlayer.Open(new Uri(mFile.PathToFile));
openedEvent.WaitOne(maxTimeToWait);
var fromThread = Dispatcher.FromThread(Thread.CurrentThread);
if (fromThread != null) fromThread.InvokeShutdown();
return mFile;
}
private void WaitForEvent(object context)
{
var mFile = (MediaFile)context;
var mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened +=
delegate
{
if (mediaPlayer.NaturalDuration.HasTimeSpan)
mFile.TimeSpanOfMediaFile = mediaPlayer.NaturalDuration.TimeSpan;
mFile.HasAudio = mediaPlayer.HasAudio;
mFile.HasVideo = mediaPlayer.HasVideo;
mFile.Success = true;
mediaPlayer.Close();
openedEvent.Set();
};
mediaPlayer.MediaFailed +=
delegate
{
mFile.Failure = true;
mediaPlayer.Close();
openedEvent.Set();
};
mediaPlayer.Open(new Uri(mFile.PathToFile));
Dispatcher.Run();
}
}
【问题讨论】:
-
查看我完成的答案。
标签: c# multithreading memory-leaks event-handling media-player