進程間通信的方式有很多,常用的方式有:
1.共享內存(內存映射文件,共享內存DLL)。
2.命名管道和匿名管道。
3.發送消息
本文是記錄共享內存的方式進行進程間通信,首先要建立一個進程間共享的內存地址,創建好共享內存地址后,一個進程向地址中寫入數據,另外的進程從地址中讀取數據。
在數據的讀寫的過程中要進行進程間的同步。
進程間數據同步可以有以下的方式
1. 互斥量Mutex
2. 信號量Semaphore
3. 事件Event
本文中進程間的同步采用 信號量Semaphore的方式同步思想類似於操作系統中生產者和消費者問題的處理方式。
在A進程中創建共享內存,並開啟一個線程用來讀取B進程向共享內存中寫入的數據,定義兩個信號量進行讀寫互斥同步
A進程中的程序代碼
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
namespace AppOne
{
public partial class AppOneMain : Form
{
const int INVALID_HANDLE_VALUE = - 1;
const int PAGE_READWRITE = 0x04;
[DllImport( " User32.dll ")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport( " User32.dll ")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
// 共享內存
[DllImport( " Kernel32.dll ", EntryPoint = " CreateFileMapping ")]
private static extern IntPtr CreateFileMapping(IntPtr hFile, // HANDLE hFile,
UInt32 lpAttributes, // LPSECURITY_ATTRIBUTES lpAttributes, // 0
UInt32 flProtect, // DWORD flProtect
UInt32 dwMaximumSizeHigh, // DWORD dwMaximumSizeHigh,
UInt32 dwMaximumSizeLow, // DWORD dwMaximumSizeLow,
string lpName // LPCTSTR lpName
);
[DllImport( " Kernel32.dll ", EntryPoint = " OpenFileMapping ")]
private static extern IntPtr OpenFileMapping(
UInt32 dwDesiredAccess, // DWORD dwDesiredAccess,
int bInheritHandle, // BOOL bInheritHandle,
string lpName // LPCTSTR lpName
);
const int FILE_MAP_ALL_ACCESS = 0x0002;
const int FILE_MAP_WRITE = 0x0002;
[DllImport( " Kernel32.dll ", EntryPoint = " MapViewOfFile ")]
private static extern IntPtr MapViewOfFile(
IntPtr hFileMappingObject, // HANDLE hFileMappingObject,
UInt32 dwDesiredAccess, // DWORD dwDesiredAccess
UInt32 dwFileOffsetHight, // DWORD dwFileOffsetHigh,
UInt32 dwFileOffsetLow, // DWORD dwFileOffsetLow,
UInt32 dwNumberOfBytesToMap // SIZE_T dwNumberOfBytesToMap
);
[DllImport( " Kernel32.dll ", EntryPoint = " UnmapViewOfFile ")]
private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport( " Kernel32.dll ", EntryPoint = " CloseHandle ")]
private static extern int CloseHandle(IntPtr hObject);
private Semaphore m_Write; // 可寫的信號
private Semaphore m_Read; // 可讀的信號
private IntPtr handle; // 文件句柄
private IntPtr addr; // 共享內存地址
uint mapLength; // 共享內存長
// 線程用來讀取數據
Thread threadRed;
public AppOneMain()
{
InitializeComponent();
init();
}
///<summary>/// 初始化共享內存數據 創建一個共享內存
///</summary>privatevoid init()
{
m_Write = new Semaphore(1, 1, "WriteMap");//開始的時候有一個可以寫
m_Read = new Semaphore(0, 1, "ReadMap");//沒有數據可讀
mapLength = 1024;
IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);
handle = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, mapLength, "shareMemory");
addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
//handle = OpenFileMapping(0x0002, 0, "shareMemory");
//addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
threadRed = new Thread(new ThreadStart(ThreadReceive));
threadRed.Start();
}
/// <summary>
/// 線程啟動從共享內存中獲取數據信息
/// </summary>
private void ThreadReceive()
{
myDelegate myI = new myDelegate(changeTxt);
while (true)
{
try
{
//m_Write = Semaphore.OpenExisting("WriteMap");
//m_Read = Semaphore.OpenExisting("ReadMap");
//handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");
//讀取共享內存中的數據:
//是否有數據寫過來
m_Read.WaitOne();
//IntPtr m_Sender = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
byte[] byteStr = new byte[100];
byteCopy(byteStr, addr);
string str = Encoding.Default.GetString(byteStr, 0, byteStr.Length);
/////調用數據處理方法 處理讀取到的數據
m_Write.Release();
}
catch (WaitHandleCannotBeOpenedException)
{
continue;
//Thread.Sleep(0);
}
}
}
//不安全的代碼在項目生成的選項中選中允許不安全代碼
static unsafe void byteCopy(byte[] dst, IntPtr src)
{
fixed (byte* pDst = dst)
{
byte* pdst = pDst;
byte* psrc = (byte*)src;
while ((*pdst++ = *psrc++) != '\0')
;
}
}
}
}
B進程向共享內存中寫入的數據
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
namespace AppTwo
{
public partial class AppTwoMain : Form
{
const int INVALID_HANDLE_VALUE = - 1;
const int PAGE_READWRITE = 0x04;
// 共享內存
[DllImport( " Kernel32.dll ", EntryPoint = " CreateFileMapping ")]
private static extern IntPtr CreateFileMapping(IntPtr hFile, // HANDLE hFile,
UInt32 lpAttributes, // LPSECURITY_ATTRIBUTES lpAttributes, // 0
UInt32 flProtect, // DWORD flProtect
UInt32 dwMaximumSizeHigh, // DWORD dwMaximumSizeHigh,
UInt32 dwMaximumSizeLow, // DWORD dwMaximumSizeLow,
string lpName // LPCTSTR lpName
);
[DllImport( " Kernel32.dll ", EntryPoint = " OpenFileMapping ")]
private static extern IntPtr OpenFileMapping(
UInt32 dwDesiredAccess, // DWORD dwDesiredAccess,
int bInheritHandle, // BOOL bInheritHandle,
string lpName // LPCTSTR lpName
);
const int FILE_MAP_ALL_ACCESS = 0x0002;
const int FILE_MAP_WRITE = 0x0002;
[DllImport( " Kernel32.dll ", EntryPoint = " MapViewOfFile ")]
private static extern IntPtr MapViewOfFile(
IntPtr hFileMappingObject, // HANDLE hFileMappingObject,
UInt32 dwDesiredAccess, // DWORD dwDesiredAccess
UInt32 dwFileOffsetHight, // DWORD dwFileOffsetHigh,
UInt32 dwFileOffsetLow, // DWORD dwFileOffsetLow,
UInt32 dwNumberOfBytesToMap // SIZE_T dwNumberOfBytesToMap
);
[DllImport( " Kernel32.dll ", EntryPoint = " UnmapViewOfFile ")]
private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport( " Kernel32.dll ", EntryPoint = " CloseHandle ")]
private static extern int CloseHandle(IntPtr hObject);
private Semaphore m_Write; // 可寫的信號
private Semaphore m_Read; // 可讀的信號
private IntPtr handle; // 文件句柄
private IntPtr addr; // 共享內存地址
uint mapLength; // 共享內存長
Thread threadRed;
public AppTwoMain()
{
InitializeComponent();
// threadRed = new Thread(new ThreadStart(init));
// threadRed.Start();
mapLength = 1024;
}
private void button1_Click( object sender, EventArgs e)
{
try
{
m_Write = Semaphore.OpenExisting( " WriteMap ");
m_Read = Semaphore.OpenExisting( " ReadMap ");
handle = OpenFileMapping(FILE_MAP_WRITE, 0, " shareMemory ");
addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
m_Write.WaitOne();
byte[] sendStr = Encoding.Default.GetBytes(textBox1.Text.ToString() + ' \0 ');
// 如果要是超長的話,應另外處理,最好是分配足夠的內存
if (sendStr.Length < mapLength)
Copy(sendStr, addr);
m_Read.Release();
}
catch (WaitHandleCannotBeOpenedException)
{
MessageBox.Show( " 不存在系統信號量! ");
return;
}
}
static unsafe void Copy( byte[] byteSrc, IntPtr dst)
{
fixed ( byte* pSrc = byteSrc)
{
byte* pDst = ( byte*)dst;
byte* psrc = pSrc;
for ( int i = 0; i < byteSrc.Length; i++)
{
*pDst = *psrc;
pDst++;
psrc++;
}
}
}
}
}