内存映射文件从内存中删除

时间:2015-04-30 08:39:05

标签: c# memory mutex

出于某种原因,当我从内存映射文件中读取几次它只是从内存中随机删除时,我不知道发生了什么。内核或GC是否从内存中删除它?如果是,我该如何阻止他们这样做?

我将一个对象序列化为Json并将其写入内存。

我在几次尝试再次阅读时遇到异常,我得到FileNotFoundException: Unable to find the specified file.

private const String Protocol = @"Global\";

写入内存映射文件的代码:

public  static  Boolean                 WriteToMemoryFile<T>(List<T> data)
        {
            try
            {
                if (data == null)
                {
                    throw new ArgumentNullException("Data cannot be null", "data");
                }

                var mapName = typeof(T).FullName.ToLower();
                var mutexName = Protocol + typeof(T).FullName.ToLower();
                var serializedData = JsonConvert.SerializeObject(data);
                var capacity = serializedData.Length + 1;

                var mmf = MemoryMappedFile.CreateOrOpen(mapName, capacity);
                var isMutexCreated = false;
                var mutex = new Mutex(true, mutexName, out isMutexCreated);
                if (!isMutexCreated)
                {
                    var isMutexOpen = false;
                    do
                    {
                        isMutexOpen = mutex.WaitOne();
                    }
                    while (!isMutexOpen);
                    var streamWriter = new StreamWriter(mmf.CreateViewStream());
                    streamWriter.WriteLine(serializedData);
                    streamWriter.Close();
                    mutex.ReleaseMutex();
                }
                else
                {
                    var streamWriter = new StreamWriter(mmf.CreateViewStream());
                    streamWriter.WriteLine(serializedData);
                    streamWriter.Close();
                    mutex.ReleaseMutex();
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

从内存映射文件中读取的代码:

public  static  List<T>                     ReadFromMemoryFile<T>()
        {
            try
            {
                var mapName = typeof(T).FullName.ToLower();
                var mutexName = Protocol + typeof(T).FullName.ToLower();

                var mmf = MemoryMappedFile.OpenExisting(mapName);
                var mutex = Mutex.OpenExisting(mutexName);
                var isMutexOpen = false;
                do
                {
                    isMutexOpen = mutex.WaitOne();
                }
                while (!isMutexOpen);

                var streamReader = new StreamReader(mmf.CreateViewStream());
                var serializedData = streamReader.ReadLine();
                streamReader.Close();
                mutex.ReleaseMutex();
                var data = JsonConvert.DeserializeObject<List<T>>(serializedData);
                mmf.Dispose();
                return data;
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }

        }

2 个答案:

答案 0 :(得分:3)

创建内存映射文件的进程必须保留对它的引用,只要您希望它存在。正是由于这个原因,使用CreateOrOpen有点棘手 - 你不知道处理内存映射文件是否会破坏它。

您可以通过向mmf.Dispose()方法添加明确的WriteToMemoryFile来轻松查看此功能 - 它将完全关闭文件。在Dispose实例的所有引用都超出范围后,mmf实例的终结器会调用WriteToMemoryFile("Hi"); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); ReadFromMemoryFile().Dump(); // Nope, the value is lost now 方法。

或者,为了让GC更加明显是罪魁祸首,你可以尝试明确地调用GC:

JsonConverter

请注意,我稍微改变了您的方法以使用简单的字符串;你真的想要生成最简单的可能的代码来重现你观察到的行为。即使只是得到AbandonedMutexException也是一种不必要的复杂情况,并且可能会导致人们甚至不尝试运行您的代码:)

作为旁注,您希望在Mutex.WaitOne时检查AbandonedMutexException - 这不是失败,这意味着您接管了互斥锁。大多数应用程序处理此错误,导致死锁以及互斥锁所有权和生命周期问题:)换句话说,将Mutex.ReleaseMutex视为成功。哦,将finally之类的东西放在AbandonedMutexException子句中是个好主意,以确保它实际发生,即使你得到一个例外。线程或进程死亡并不重要(这只会导致其他一个参与者获得return false;),但是如果你只是得到一个例外,你就可以处理&#34;使用exec(),在关闭所有应用程序并重新开始之前,互斥锁不会被释放:)

答案 1 :(得分:0)

显然,问题在于,如Luaan所解释的那样,MMF会失去其背景。但仍然没有人解释如何执行它:

  1. 代码&#39;写入MMF文件&#39;必须在一个单独的异步线程上运行。
  2. 代码&#39;从MMF&#39;一旦阅读完毕,将通知MMF已被阅读​​。例如,通知可以是文件中的标志。
  3. 因此,异步线程运行&#39;写入MMF文件&#39;只要从第二部分读取MMF文件就会运行。因此,我们创建了内存映射文件有效的上下文。