Shared memory synchronization between c++ and c#
c#, c++, ipc, locking, visual-studio
Solution
You will need a named synchronization object. Maybe a mutex.
In C++ you can call CreateMutex while in C# there is the Mutex class that handles it for you.
Both links come with examples, maybe you give it a try and come back if you encounter a specific problem.
Problem
I've written two little programs. A C++ program that writes a string in a shared memory, and a C# program that reads the string from shared memory and writes it on the console. Programs work well, but at the moment I write the string in a timed loop, and I read it from another timed loop, with same frequency. What I want to do is to create some sort of locking. I want to use a semaphore/mutex/whatever, so from C# I cannot read shm while C++ program is writing it, and viceversa. I've read something like named mutex and semamphore. I can create them in both programs, but I really don't know how to use them properly. C++ program: MemoryWriter.h ``` #ifndef MEMORYWRITER_H_ #define MEMORYWRITER_H_ #include <windows.h> #include <string> #include <random> class MemoryWriter { public: MemoryWriter(const std::wstring& name, size_t size); std::string createRandomData() const; void write(const std::string& data); private: char getRandomCharacter() const; void createSharedMemory(); private: std::wstring m_memoryName; size_t m_memorySize = 0; HANDLE m_shmHandler = 0; }; #endif // !MEMORYWRITER_H_ ``` MemoryWriter.cpp ``` #include "MemoryWriter.h" #include <random> #include <iostream> /////////////////////////////////////////////////////////////////////////////// // USING SECTION // /////////////////////////////////////////////////////////////////////////////// using std::string; /////////////////////////////////////////////////////////////////////////////// // CONSTANTS SECTION // /////////////////////////////////////////////////////////////////////////////// const char MinCharacter{ 'A' }; const char MaxCharacter{ 'z' }; /////////////////////////////////////////////////////////////////////////////// // PUBLIC SECTION // /////////////////////////////////////////////////////////////////////////////// MemoryWriter::MemoryWriter(const std::wstring& name, size_t size) : m_memoryName(name), m_memorySize(size) { createSharedMemory(); } string MemoryWriter::createRandomData() const { string data; for (size_t i = 0; i < m_memorySize; i++) { data += getRandomCharacter(); } return data; } void MemoryWriter::write(const string& data) { if (!m_shmHandler) { return; } auto buffer = MapViewOfFile(m_shmHandler, FILE_MAP_ALL_ACCESS, 0, 0, m_memorySize); if (NULL == buffer) { std::cerr << "Cannot use MapViewOfFile: null buffer." << std::endl; return; } CopyMemory(buffer, data.c_str(), data.size()); } ////////////////////////////////////////////////////////////////////////////// // PRIVATE SECTION // ////////////////////////////////////////////////////////////////////////////// char MemoryWriter::getRandomCharacter() const { return MinCharacter + rand() % 24; } void MemoryWriter::createSharedMemory() { m_shmHandler = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, m_memoryName.c_str()); if (!m_shmHandler) { m_shmHandler = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, m_memorySize, m_memoryName.c_str()); } } ``` main.cpp ``` #include "MemoryWriter.h" #include <iostream> #include <string> #include <thread> int main(int argc, char* argv[]) { std::wstring memoryName{ L"shm_1" }; size_t memorySize{ 80 }; MemoryWriter writer(memoryName, memorySize); while (true) { std::string data; data = writer.createRandomData(); writer.write(data); std::cout << "C++: Written in shm - " << data << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } return 0; } ``` C# program ``` using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SharedMemoryReader { class Program { static void Main(string[] args) { string shmName = "shm_1"; int shmSize = 80; var shm = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateOrOpen(shmName, shmSize); while (true) { var view = shm.CreateViewStream(); if (view == null) { continue; } byte[] data = new byte[shmSize]; view.Read(data, 0, shmSize); string text = System.Text.Encoding.Default.GetString(data); System.Console.WriteLine("C#: Read from shm - " + text); System.Threading.Thread.Sleep(100); } } } } ```