Problem
Did you ever encounter a requirement which require your application to get some data from another application? For instance, you have created an application A, the value from one of the variable in application A is required to be shared with other application B, C and D, all these application are going to run in one same server. What would you do?
Solution
Today's topic cover about Memory Mapped File. The fastest way to access data no doubt is direct access from the memory. In .NET 4.0, it introduced Memory Mapped File, a file that contain the contents of virtual memory. This file can be read and write by any program as long as you know the file location. The file content is mapped directly to the virtual memory. Therefore, this virtual memory can become a shared memory which can be accessible directly by any application without any constraint.
Memory Mapped File support persisted and non-persisted file mode, persisted mode will keep the data whenever the last process working with the file has ended, the non-persisted mode will not the keep the data, it will be cleared by garbage collector after the last process has finished working on it. For more info, refer HERE and the concept from HERE.
Memory Mapped File can be used to create shared memory, I can create a generic component which allow me to store any object into it and share it with all the application. But, in this post, I just keep it simple and I am writing a simple string shared memory. The string value can be read and changed. The string value changes will be reflected in all the application immediately. Also, the value will be persisted, after the process is being killed or server get rebooted, the string value will still be available.
There is one challenge here. The file can only be accessible by one process one thread at one time because the file is locked automatically whenever a thread is accessing it. Normally, we can use the lock syntax to block other threads entering critical section of code until it has been released, but in order to lock processes, we have to use mutual exclusion (mutex).
Memory Mapped File is available under the System.IO namespace as long as your application target framework is .NET 4.0 or later. Any external assembly reference is not required.
This is how the shared memory code look like:There is one challenge here. The file can only be accessible by one process one thread at one time because the file is locked automatically whenever a thread is accessing it. Normally, we can use the lock syntax to block other threads entering critical section of code until it has been released, but in order to lock processes, we have to use mutual exclusion (mutex).
Memory Mapped File is available under the System.IO namespace as long as your application target framework is .NET 4.0 or later. Any external assembly reference is not required.
using
System.IO;
using System.IO.MemoryMappedFiles;
public class SharedMemory
: IDisposable
{
//Keep the mutex as static to
prevent early garbage collection
private static Mutex
_mutex;
private static object
_numLock;
static
SharedMemory()
{
_numLock = new object();
if
(!Mutex.TryOpenExisting("sharedMutex",
out _mutex))
{
_mutex = new Mutex(true,
"sharedMutex");
}
}
public void
Set(string value)
{
//lock thread
lock
(_numLock)
{
//lock process with
mutex
if
(_mutex.WaitOne())
{
//access memory
mapped file (need persistence)
using
(var memMapFile = MemoryMappedFile.CreateFromFile(
@"D:\temp\SharedMemoryMap",
//file location
FileMode.OpenOrCreate, //create new file if not
exist, open if exist
"shared",
//map name
1024)) //size
{
//update
the number to memory view
using
(var stream = memMapFile.CreateViewStream())
using
(var writer = new BinaryWriter(stream))
{
writer.Write(value);
}
}
//release the mutex
for other process to access the memory mapped file
_mutex.ReleaseMutex();
}
}
}
public string
Get()
{
string
value = null;
//lock thread
lock
(_numLock)
{
//lock process with
mutex
if
(_mutex.WaitOne())
{
//access memory
mapped file (need persistence)
using
(var memMapFile = MemoryMappedFile.CreateFromFile(
@"D:\temp\SharedMemoryMap",
//file location
FileMode.OpenOrCreate, //create new file if not
exist, open if exist
"shared",
//map name
1024)) //size
{
//get
last number from memory view
using
(var stream = memMapFile.CreateViewStream())
using
(var reader = new BinaryReader(stream))
{
value =
reader.ReadString();
}
}
//release the mutex
for other process to access the memory mapped file
_mutex.ReleaseMutex();
}
}
return
value;
}
public void
Dispose()
{
if
(_mutex != null)
_mutex.Dispose();
}
}
Now, I have created and started a few console application which all are having the same shared memory assembly reference. Then, call the Get() function to retrieve the memory value, then the Set() function to change the value.
class Program
{
static void
Main(string[] args)
{
bool
quit = false;
using
(SharedMemory mem = new SharedMemory())
{
do
{
Console.WriteLine("Current
value: " + mem.Get());
Console.Write("New
value: ");
string
input = Console.ReadLine();
if
(input == "quit")
quit = true;
else
mem.Set(input);
}
while
(!quit);
}
}
}
Close all the console windows, then reopen one back. You will still be able to get the last persisted string value which you had entered in the last closed console.
If you go to the memory mapped file location which you had specified in the code, you will see a file is created in the folder and the content is in binary form. That's the value in the virtual memory.
If you are interested with my source code, feel free to download from HERE.
whose the dumbass sob who posted this shit lol
ReplyDelete