News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Shared Memory using Masm

Started by Paulo, September 09, 2013, 09:29:41 PM

Previous topic - Next topic

Paulo

Hi all

Can anyone give me some pointers on how to go about allocating some memory (say 20MBytes) that can be shared with other apps.
I have an app that runs all the time and logs (appends)  a value every twenty seconds or so, what I need is for another app to periodically read the data that the other app
wrote to the log.
Obviously writing to hard drive is not good as after a few months the hard drive is really getting whacked and thus prefer to use RAM.

Thanks in advance.
Paulo.

jj2007

Hi Paulo,

Perhaps you should give some more info on size and periodicity of your app. You write that the "server" writes a value (say: a double, 8 bytes) every twenty seconds, i.e. 34560 bytes per day. That is negligible for a hard disk, so why are you worried?

Does the "client" need the full log file, or just recent records?

Standard answers are memory-mapped files and WM_COPYDATA messages, but it really depends on the circumstances.

dedndave

you can also create cutsom messages
but - if the second app fires up every 20 seconds - that's wearing on the hard drive, too - lol
you haven't saved anything by not doing it with a single app

how much data is to be saved svery 20 seconds ?

Paulo

Hi

OK, more details:

App one ("server") is running all the time and writes 50 bytes every 20 seconds. (216 000 bytes per day).
App two ("client") will occasionally (perhaps 4 times a day) read the whole data so far for that day.

The days data is then flushed by the server at midnight.

I was under the impression that there are two types of wear and tear for hard drives:

1) The actual seeking for files (read or write)
2) Writing the actual data.

dedndave

oh - 4 times a day isn't so bad
200 kb is nothing compared to the size of computer memory these days

WM_COPYDATA would work well - or a custom message

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644931%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644947%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649011%28v=vs.85%29.aspx

all you need is the window handle(s) in order to send messages back and forth
when the second app fires up, it can look for the first window
there are a few ways to do that - search for it by window title, or class name, etc
FindWindow, EnumWindows and so on

jj2007

#5
Paulo,

For such a small amount of data, the simplest solution is really shared memory using a DLL. The attachment is set up for use with RichMasm, but the DLL code below works also with qEditor etc

The DLL:

include \masm32\include\masm32rt.inc

ShareLen=256*1024        ; 256k

MyData segment shared 'bss'
OneDay LABEL BYTE
  ORG $+ShareLen-1   ; looks complicated but avoids a MASM bug
  db ?
MyData ends

.code
GetPtr2SharedMem proc        ; $export
  mov eax, offset OneDay
  retn
GetPtr2SharedMem endp

LibMain proc instance:DWORD, reason:DWORD, unused:DWORD
    m2m eax, TRUE
    ret
LibMain endp

end LibMain

Sample code calling the DLL:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Dll "SharedMemInDLL"
  Declare GetPtr2SharedMem, 0
  mov edi, GetPtr2SharedMem()        ; get current content
  MsgBox 0, Cat$("Write new string?"+CrLf$+edi), "Hi", MB_YESNO
  .if eax==IDYES
        invoke MbCopy, edi, Cat$("This string was written on "+Date$+", "+Time$), -1
        MsgBox 0, "Now launch a second instance and see the string", "Hi", MB_OK
  .endif
  Exit
end start

Paulo

dedndave

According to Microsoft:
"An application sends the WM_COPYDATA message to pass data to another application. "
Isn't this the opposite of what I need? (or perhaps I'm having a nebulous moment  :biggrin: having a lot of those lately).
i.e. the receiving app should first check if the other app is running (like you say via title or class) then issue a "need some data" message.

I was thinking more along the lines of the "server" app creates an array (of sorts) in memory and saves the address of that array in a file.
It only does this at start up as the address will be valid until the app closes and relinquishes that memory and deletes the file containing the memory address.
The memory array is organized so that the first 4 bytes contains a count of the bytes that it has written so far to memory.
These 4 bytes are updated every twenty seconds once the app writes the next 50 bytes.

The second app then starts up and checks for the existence of the file which has the memory address in it.
If it exists, it reads it then reads the first 4 bytes of the array in memory telling it how many bytes it must fetch from the memory.

Perhaps a bit more convoluted but I like the isolation between the two apps, i.e. no sending of messages and waiting if the other app has got it.

@jj2007

Your DLL method look interesting, I will investigate.

Tedd

A disk write must be a whole sector as a minimum, so even if you only write a single byte, a whole sector must still be written. So constantly writing will produce wear. However, a modern hard-drive should be able to handle 5 years of constant reading and writing; but why waste it. And it just means the disk is unnecessarily busy for no good reason.

The OS will cache your writes to an extent, so if you write frequently enough, they will be collected and written as full sectors, but this window is only a few seconds.

Rather than shared memory (all results lost if anything goes wrong), you can still buffer your writes, and flush to file periodically.
Allocate a medium sized buffer (16--32kB) and write your results to this every 20 seconds, then when it gets 'full,' open the file (with append) and write the collected results to the file, close the file, and start filling the buffer again. The server will be able to pick up the results from this file as needed; if you strictly want up-to-the-second results, you could have the server send a message to force the client to flush its buffer, and then the server reads from the file.
Potato2

jj2007

Quote from: Tedd on September 09, 2013, 11:26:09 PM
Rather than shared memory (all results lost if anything goes wrong), you can still buffer your writes, and flush to file periodically.

You should combine the two, of course. You need to add periodic saving to the simple example above, which was only intended to demonstrate how shared memory works.

Paulo

Hi Tedd

Nice idea that.
Perhaps I make the buffer hold say 10 readings (~3 minutes worth of data) thereby reducing the write to file frequency by a factor
of ten and at the same time if something goes wrong with the app and it has to be restarted, not much data is lost.

Come to think of it, for 10 X 50 bytes I don't even need a buffer, just store it in a variable.

Paulo

OK decided on Tedd's idea.

@jj2007

I really like your DLL, I can see several uses for it, thank you.

@dedndave

Thanks for showing me WM_USER.
I didn't know one could send private messages.

jj2007

Quote from: Paulo on September 09, 2013, 11:51:54 PM
I really like your DLL
...
I didn't know one could send private messages.

Paulo,

I updated the example above, it's now "bss" to reduce the DLL size.

Note that the "server" can send messages also as a console app, e.g. for informing the "client" that new data are available (in case synchronisation is needed); but of course, there must be a message loop at the receiving end.

Paulo

Thanks for the update jj2007, but why is the source in rtf format?

qWord

If some kind of server-client structure is already available, you can also use UDP for sending the log data when they arise.
MREAL macros - when you need floating point arithmetic while assembling!

Paulo

Quote from: qWord on September 10, 2013, 01:22:15 AM
If some kind of server-client structure is already available, you can also use UDP for sending the log data when they arise.

Nice idea too but no server-client structure in place.