c ++和c#之间的共享内存同步

时间:2016-10-25 10:44:13

标签: c# c++ visual-studio locking ipc

我写了两个小程序。将字符串写入共享内存的C ++程序,以及从共享内存中读取字符串并将其写入控制台的C#程序。

程序运行良好,但目前我在定时循环中编写字符串,然后从另一个定时循环读取它,频率相同。

我想要做的是创建某种锁定。我想使用信号量/互斥量/无论如何,所以从C#开始,当C ++程序编写它时,我无法读取shm,反之亦然。

我读过像mutex和semamphore这样的东西。我可以在两个程序中创建它们,但我真的不知道如何正确使用它们。

C ++程序: 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#程序

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);
                }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

您将需要一个命名的同步对象。也许是mutex

在C ++中,你可以在C#中调用CreateMutex,有Mutex类为你处理它。

这两个链接都带有示例,如果您遇到特定问题,可能会尝试一下并回来。

答案 1 :(得分:1)

我建议使用命名信号量或命名互斥锁...命名对象是系统范围的

来自MSDN Interprocess Synchronization

  

命名对象为进程共享对象提供了一种简便方法   手柄