熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

使用共享內存在進程之間傳送數據

2022-06-13   來源: .NET編程 

  今日在項目中碰到一個問題就是一個程序的兩個進程之間需要頻繁的傳送數據具體的來說是一個需要頻繁的發送數據而另一個實例需要頻繁的訪問獲得這些數據當然這個問題是有很多解的例如數據庫再例如文件可是因為這個頻繁程度太高了例如一秒鐘十次在這種情況下使用數據庫或者是文件可能都不是一個Good Idea

  Update: 其實開始想到的方案還包括Remoting Socket之類的不過明顯的是小題大做殺雞用牛刀了呵呵所以最後也就放棄了

  那麼什麼解決方案好呢?眾所周知內存的速度是除了CPU緩存外最快的當然是我們的首選了可是看遍了Net的類庫也沒有找到可以用來實現這個方案的辦法看來只能依靠Win API了在網上得到資料可以使用API開辟共享內存從而達到在不同的進程之間共享數據的可能

  關鍵API類

  view sourceprint?public static class API

  {

  [DllImport(userdll CharSet = CharSetAuto)]

  public static extern IntPtr SendMessage(IntPtr hWnd int Msg int wParam IntPtr lParam);

  [DllImport(Kerneldll CharSet = CharSetAuto)]

  public static extern IntPtr CreateFileMapping(int hFile IntPtr lpAttributes uint flProtect uint dwMaxSizeHi uint dwMaxSizeLow string lpName);

  [DllImport(Kerneldll CharSet = CharSetAuto)]

  public static extern IntPtr OpenFileMapping(int dwDesiredAccess [MarshalAs(UnmanagedTypeBool)] bool bInheritHandle string lpName);

  [DllImport(Kerneldll CharSet = CharSetAuto)]

  public static extern IntPtr MapViewOfFile(IntPtr hFileMapping uint dwDesiredAccess uint dwFileOffsetHigh uint dwFileOffsetLow uint dwNumberOfBytesToMap);

  [DllImport(Kerneldll CharSet = CharSetAuto)]

  public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

  [DllImport(Kerneldll CharSet = CharSetAuto)]

  public static extern bool CloseHandle(IntPtr handle);

  [DllImport(kernel EntryPoint = GetLastError)]

  public static extern int GetLastError();

  [DllImport(msvcrtdll SetLastError = true)]

  public static extern int memcmp(IntPtr ptr IntPtr ptr int count);

  [DllImport(msvcrtdll SetLastError = true)]

  public static extern unsafe int memcmp(void* ptr void* ptr int count);

  [DllImport(ntdlldll)]

  public static extern int RtlCompareMemory(IntPtr Destination IntPtr Source int Length);

  public const int ERROR_ALREADY_EXISTS = ;

  public const int FILE_MAP_COPY = x;

  public const int FILE_MAP_WRITE = x;

  public const int FILE_MAP_READ = x;

  public const int FILE_MAP_ALL_ACCESS = x | x;

  public const int PAGE_READONLY = x;

  public const int PAGE_READWRITE = x;

  public const int PAGE_WRITECOPY = x;

  public const int PAGE_EXECUTE = x;

  public const int PAGE_EXECUTE_READ = x;

  public const int PAGE_EXECUTE_READWRITE = x;

  public const int SEC_COMMIT = x;

  public const int SEC_IMAGE = x;

  public const int SEC_NOCACHE = x;

  public const int SEC_RESERVE = x;

  public const int INVALID_HANDLE_VALUE = ;

  }

  代碼實現

  view sourceprint?public enum MemoryResult

  {

  Success

  NotInitialized

  NoChange

  Failed

  }

  public class ShareMemory<T> : IDisposable

  where T : class

  {

  IntPtr m_hSharedMemoryFile = IntPtrZero;

  IntPtr m_pwData = IntPtrZero;

  bool m_bAlreadyExist = false;

  bool m_bInit = false;

  long m_MemSize = ;

  int m_size;

  byte[] m_lastData;

  public ShareMemory()

  {

  }

  ~ShareMemory()

  {

  Close();

  }

  /// <summary>

  /// 初始化共享內存

  /// </summary>

  public MemoryResult Init(string strName)

  {

  m_size = ; //固定K

  var lngSize = m_size;

  if (lngSize <= || lngSize > x) lngSize = x;

  m_MemSize = lngSize;

  if (strNameLength > )

  {

  //創建內存共享體 (INVALID_HANDLE_VALUE)

  m_hSharedMemoryFile = APICreateFileMapping(APIINVALID_HANDLE_VALUE IntPtrZero (uint)APIPAGE_READWRITE (uint)lngSize strName);

  if (m_hSharedMemoryFile == IntPtrZero)

  {

  m_bAlreadyExist = false;

  m_bInit = false;

  return MemoryResultFailed; //創建共享體失敗

  }

  else

  {

  if (APIGetLastError() == APIERROR_ALREADY_EXISTS)  //已經創建

  {

  m_bAlreadyExist = true;

  }

  else                                         //新創建

  {

  m_bAlreadyExist = false;

  }

  }

  //

  //創建內存映射

  m_pwData = APIMapViewOfFile(m_hSharedMemoryFile APIFILE_MAP_WRITE (uint)lngSize);

  if (m_pwData == IntPtrZero)

  {

  m_bInit = false;

  APICloseHandle(m_hSharedMemoryFile);

  return MemoryResultFailed; //創建內存映射失敗

  }

  else

  {

  m_bInit = true;

  if (m_bAlreadyExist == false)

  {

  //初始化

  }

  }

  //

  }

  else

  {

  return MemoryResultFailed; //參數錯誤

  }

  return MemoryResultSuccess;     //創建成功

  }

  /// <summary>

  /// 關閉共享內存

  /// </summary>

  public void Close()

  {

  if (m_bInit)

  {

  APIUnmapViewOfFile(m_pwData);

  APICloseHandle(m_hSharedMemoryFile);

  }

  }

  /// <summary>

  /// 讀數據

  /// </summary>

  public unsafe MemoryResult Read(out T obj)

  {

  obj = default(T);

  byte[] bytData = new byte[m_size];

  if (m_bInit)

  {

  MarshalCopy(m_pwData bytData m_size);

  if (m_lastData != null)

  {

  fixed (byte* p = m_lastData)

  {

  fixed (byte* p = bytData)

  {

  if (mcmp(p p m_size) == )

  return MemoryResultNoChange;

  }

  }

  }

  m_lastData = bytData;

  var fmt = new BinaryFormatter();

  using (var ms = new MemoryStream(bytData))

  {

  try

  {

  obj = (T)fmtDeserialize(ms);

  }

  catch (SerializationException)

  {

  return MemoryResultFailed;

  }

  }

  }

  else

  {

  return MemoryResultNotInitialized; //共享內存未初始化

  }

  return MemoryResultSuccess;     //讀成功

  }

  /// <summary>

  /// 寫數據

  /// </summary>

  public MemoryResult Write(T obj)

  {

  var fmt = new BinaryFormatter();

  byte[] bytData;

  if (obj is byte[])

  bytData = obj as byte[];

  else

  {

  using (var ms = new MemoryStream())

  {

  fmtSerialize(ms obj);

  bytData = msToArray();

  }

  }

  if (m_bInit)

  MarshalCopy(bytData m_pwData bytDataLength);

  else

  return MemoryResultNotInitialized; //共享內存未初始化

  return MemoryResultSuccess;     //寫成功

  }

  #region IDisposable Members

  public void Dispose()

  {

  Close();

  }

  #endregion

  }

  使用也很簡單

  view sourceprint?寫數據

  if (mem == null)

  {

  mem = new ShareMemory<ChannelStatus[]>();

  memInit(ChannelStatus);

  }

  var xml = PhoneCallHelperSendRequest(PhoneCallActiongetChStatus);

  foreach (XmlElement ele in xmlDocumentElementSelectNodes(chStatus))

  {

  var status = GetChannelStatusFromXElement(ele);

  _status[statusChannel] = status;

  }

  memWrite(_statusValuesToArray());

  讀數據

  using (var mem = new ShareMemory<ChannelStatus[]>())

  {

  if (memInit(ChannelStatus) != MemoryResultSuccess)

  throw new Exception(內存初始化失敗);

  ChannelStatus[] status;

  if (memRead(out status) == MemoryResultSuccess)

  return status;

  return null;

  }


From:http://tw.wingwit.com/Article/program/net/201311/13598.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.