Windows based shared memory using events
Posted: Thu May 12, 2016 1:20 am
I was working on an issue with pipelining multiple updates into a single process in regards to a database product, when I started thinking about sharing memory with multiple processes, and using events to control access. Here are two processes, one a producer, and one a consumer. I've used to Windows events to keep one process from stepping on the other. No real use for it, just an interesting concept.
The producer process must be started first. It created the shared memory area based upon a name, and two events. It also writes an initial string to the shared memory, then sets a read event, then waits on a send event trigger. The consumer process reads in the memory, sets a write event, then waits on a read event trigger.
The producer process must be started first. It created the shared memory area based upon a name, and two events. It also writes an initial string to the shared memory, then sets a read event, then waits on a send event trigger. The consumer process reads in the memory, sets a write event, then waits on a read event trigger.
Code: Select all
; shm_producer.pb
EnableExplicit
Define version.s = "1.0.01e"
Define hMap.i
Define result.i
Define mapName.s = "SharedMapName"
Define readEventNumber.i
Define sendEventNumber.i
Define sendStr.s = ""
Define mapSize.i = 16384
Define stringLen.i
readEventNumber = CreateEvent_(0, 0, 0, "read_" + mapName + "_event")
sendEventNumber = CreateEvent_(0, 0, 0, "send_" + mapName + "_event")
; procedure to write data to the shared memory map
Procedure.i WriteMapString(*mapName, *sendMemory, stringLen)
Protected hFileMap.i
Protected *mapView
Protected retValue.i = #False
hFileMap = OpenFileMapping_(#FILE_MAP_WRITE, 0, *mapName)
If hFileMap
*mapView = MapViewOfFile_(hFileMap, #FILE_MAP_WRITE, 0, 0, 0)
If *mapView
CopyMemory(*sendMemory, *mapView, stringLen)
PokeA(*mapView + stringLen, 0)
retValue = #True
UnmapViewOfFile_(*mapView)
Else
retValue = -2
EndIf
CloseHandle_(hFileMap)
Else
retValue = -1
EndIf
ProcedureReturn retValue
EndProcedure
; use the #INVALID_HANDLE_VALUE to tell the system to use memory, not a physical file!
hMap = CreateFileMapping_(#INVALID_HANDLE_VALUE, #Null, #PAGE_READWRITE, 0, mapSize + 1, @mapName)
OpenConsole("Shared Map Producer, version: " + version)
sendStr = "Started Shared Map Producer"
stringLen = Len(sendStr)
result = WriteMapString(@mapName, @sendStr, stringLen)
If result > 0
PrintN("Send to shared Map, initial value sent is: " + sendStr + ", packet sent ok")
Else
PrintN("Error writing data to shared map, process will terminate, result = " + Str(result))
Input()
End
EndIf
Repeat
Print("Enter text To send, or press <enter> to quit: ")
sendStr = Input()
stringLen = Len(sendStr)
If stringLen > 0
If stringLen > mapSize
stringLen = mapSize
sendStr = LSet(sendStr, stringLen)
EndIf
result = WriteMapString(@mapName, @sendStr, stringLen)
SetEvent_(readEventNumber)
WaitForSingleObject_(sendEventNumber, #INFINITE)
Else
SetEvent_(readEventNumber)
Break
EndIf
ForEver
CloseHandle_(hMap)
CloseConsole()
End
; IDE Options = PureBasic 5.42 LTS (Windows - x64)
; CursorPosition = 17
; FirstLine = 3
; Executable = shm_producer.exe
; DisableDebugger
; HideErrorLog
; CompileSourceDirectory
; EnableCompileCount = 9
; EnableBuildCount = 9
; EnableExeConstant
Code: Select all
; shm_consumer.pb
EnableExplicit
Define version.s = "1.0.01e"
Define lenSent.i
Define sentText.s
Define mapName.s = "SharedMapName"
Define readEventNumber.i
Define sendEventNumber.i
Define eventNumber.i
Define firstTime.i = #True
Define *recvString = AllocateMemory(16384)
readEventNumber = CreateEvent_(0, 0, 0, "read_" + mapName + "_event")
sendEventNumber = CreateEvent_(0, 0, 0, "send_" + mapName + "_event")
; procedure to open he shared memory map, and read the data
Procedure.i GetMapPointer(*mapName, *recvMemory)
Protected lenSent.i = 0
Protected *mapView
Protected hFileMap.i
Protected sentText.s
hFileMap = OpenFileMapping_(#FILE_MAP_READ, 0, *mapName)
If hFileMap
*mapView = MapViewOfFile_(hFileMap, #FILE_MAP_READ, 0, 0, 0)
If *mapView
sentText = PeekS(*mapView)
lenSent = Len(sentText)
UnmapViewOfFile_(*mapView)
EndIf
CloseHandle_(hFileMap)
If lenSent
lenSent = PokeS(*recvMemory, sentText, lenSent)
EndIf
EndIf
ProcedureReturn lenSent
EndProcedure
OpenConsole("Shared Map Consumer, version: " + version)
Repeat
lenSent = GetMapPointer(@mapName, *recvString)
If lenSent > 0
sentText = PeekS(*recvString, lenSent)
PrintN("Read Map = " + Str(lenSent) + " bytes received: " + sentText)
If firstTime
firstTime = #False
EndIf
SetEvent_(sendEventNumber)
WaitForSingleObject_(readEventNumber, #INFINITE)
Else
Break
EndIf
ForEver
If firstTime
PrintN("The shared memory producer must be started first!")
Input()
EndIf
CloseConsole()
End
; IDE Options = PureBasic 5.42 LTS (Windows - x64)
; CursorPosition = 18
; FirstLine = 3
; Executable = shm_consumer.exe
; DisableDebugger
; HideErrorLog
; CompileSourceDirectory
; EnableCompileCount = 11
; EnableBuildCount = 11
; EnableExeConstant