Проблемы кругового буфера карты памяти маршала - PullRequest
0 голосов
/ 24 января 2012

В течение последнего месяца я работал над реализацией общей памяти / циклического буфера.Я использовал основные понятия класса MemMap, представленные по адресу:

http://www.codeproject.com/Articles/10797/Using-FileMapping-on-NET-as-IPC

Однако я расширил его с помощью многих других функций.Вот краткое объяснение моей цели:

  1. Создание общей памяти для записи данных в кольцевой буфер
  2. Подключение к общей памяти из другого приложения для чтения данных
  3. Когда некоторыеважные параметры данных изменяются на стороне автора, закрывают карты и открывают новые, которые имеют соответствующий размер.Читатель получает уведомление об этом изменении, а затем подключается к новым картам и продолжает чтение.

Проблема возникает после повторной инициализации устройства записи.Читатель прекрасно подключается, потому что я сохраняю одну карту памяти для передачи имен новых карт.Однако через некоторое время читатель или писатель столкнется с «Попытка записи / чтения защищенной памяти исключения».Что еще хуже, это не всегда происходит, и не имеет значения, больше или меньше новые карты, чем предыдущие.

Я правильно использую мьютексы, и индексы циклического буфера хорошо обрабатываются.

Там есть довольно много кода, который нужно показать, так что если у вас есть предчувствие и вы не хотите его читать, тогда я буду признателен за ваш совет: D

Мой код несколькона более позднем этапе, поэтому я покажу только вероятных подозреваемых, чтобы избежать путаницы:

Для подключения считывателя к существующей карте:

''' <summary>
''' For connecting to existing memory map
''' </summary>
''' <param name="Name"></param>
''' <remarks></remarks>
Public Sub New(ByVal Name As String)
    mapHandle = OpenFileMapping(PAGE_READONLY, 0, "Global/" + Name) 'Connect to pre-existing map
    If mapHandle = 0 Then
        Throw New System.Exception("FileMapping:" + Name + " error:" + GetLastError.ToString)
    End If

    mapName = "Global/" + Name
    mapAddress = MapViewOfFile(mapHandle, FileMapAccess.FILE_MAP_ALL_ACCESS, 0, 0, 0)
    If mapAddress = 0 Then
        CloseHandle(mapHandle)
        Throw New System.Exception("MapViewOfFile error:" + GetLastError.ToString)
    End If
    mapPointer = New IntPtr(mapAddress)
End Sub

Для создания ПИСАТЕЛЯ:

   ''' <summary>
''' For creating new memory map
''' </summary>
''' <param name="Name">
''' Unique name to associate with map.
''' </param>
''' <param name="Size">
''' Total bytes to allocate for map.
''' </param>
''' <remarks></remarks>
Public Sub New(ByVal Name As String, ByVal Size As Integer)
    mapHandle = CreateFileMapping(0, IntPtr.Zero, PAGE_READWRITE, 0, Size, "Global/" + Name)
    If mapHandle = 0 Then
        Throw New System.Exception("FileMapping:" + Name + " error:" + GetLastError.ToString)
    Else

        '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        'We need to connect if pre-existing memory map
        If GetLastError = ERROR_ALREADY_EXISTS Then
            IsNew = False          'Create accesible flag
            CloseHandle(mapHandle) 'Close the map we just created
            mapHandle = OpenFileMapping(PAGE_READONLY, 0, "Global/" + Name) 'Connect to pre-existing map
            If mapHandle = 0 Then
                Throw New System.Exception("FileMapping:" + Name + " error:" + GetLastError.ToString)
            End If
        End If
        '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    End If

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    mapName = "Global/" + Name
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    mapSize = Size
    mapAddress = MapViewOfFile(mapHandle, FileMapAccess.FILE_MAP_ALL_ACCESS, 0, 0, 0) 'mod E.L.
    If mapAddress = 0 Then
        CloseHandle(mapHandle)
        Throw New System.Exception("MapViewOfFile error:" + GetLastError.ToString)
    End If
    mapPointer = New IntPtr(mapAddress)
End Sub

Запись удваивается в память:

Public Sub writeDoubles(ByVal offset As Integer, ByVal values_ As Double(), Optional ByVal startIdx As Integer = 0, Optional ByVal length As Integer = 0)
    If length = 0 Then length = values_.Length
    Marshal.Copy(values_, startIdx, New IntPtr(mapPointer.ToInt32 + offset), length)

Чтение удваивается:

   Public Sub readDoubles(ByVal offset As Integer, ByRef destArray() As Double, ByVal length As Integer, Optional ByVal startIndex As Integer = -1)
    If startIndex < 0 Then startIndex = 0
    Marshal.Copy(New IntPtr(mapPointer.ToInt32 + offset), destArray, startIndex, length)
End Sub

Детерминированная очистка памяти:

   Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
    ' Check to see if Dispose has already been called.
    If Not Me.disposed Then
        ' If disposing equals true, dispose all managed 
        ' and unmanaged resources.
        If disposing Then
            ' Dispose managed resources
        End If

        Dim closeHandleResult As Integer
        Dim unmapResult As Boolean
        'Clean up unmanaged resources here.
        closeHandleResult = CloseHandle(mapHandle)  'Successful = 1 
        unmapResult = UnmapViewOfFile(mapPointer)   'Successful = true

        If closeHandleResult = 1 And unmapResult Then
            'Reinitialize map pointer if memory deallocation was successful
            mapPointer = IntPtr.Zero
            'Note disposing has completed, only gets set 
            'if memory deallocation was successful
            disposed = True
        End If
    End If 'Not Me.disposed
End Sub
...