如何实现开辟一块共享内存和多线程访问该内存?
有一个服务进程S,它包含大量的数据,系统中还有另外几个进程,定义为:进程a,进程b,进程c
现在进程a、b、c都要对服务进程S进行访问,且进行数据的读写交互,且保证每个进程当前读S进程的数据是最新的。
我个人认为进程S需要开辟一块内存区域,且进程a,b,c都要对该内存进行访问和数据的通信。
但是C#如何开辟内存呢?进程之间是怎么通信的呢?有如何保证每个进程得到的服务进程的数据都是最新的呢?
网上也查了一些资料,搞得一头雾水,请牛人们给些指点,谢谢!
[解决办法]
memory file mapping
内存映射文件, windows 上性能最好的 ipc 进程通信
[解决办法]
你要在多进程共享内存,还是多线程共享内容,
多线程共享内存很容易实现,每个线程访问的内存空间其实都是共享的,所以所有的静态变量都可以作为多个线程共享的内存空间,
进程就麻烦了,只能用内存映射文件,
[解决办法]
进程之间的通讯,最好用socket,比较标准,
[解决办法]
用socket,弄个服务器,在服务器存储数据,所有进程从服务器取,也更新服务器。
其实更简单的方法,是webservice,wcf或remoting
[解决办法]
同进程 ,多线程。 一个全局变量就可以
多进程。可以用 webservice 等来实现。
[解决办法]
多进程间通讯使用共享内存算是一种比较好的解决方案, QQ游戏大厅, 与QQ游戏之间通讯就是采用的这种方式 .
C#实现可以参考 :
http://blog.csdn.net/yefanqiu/article/details/1717458
[解决办法]
进程共享:
可以使用进程继承,DuplicateHandle进程句柄复制,还有个命名对象。。
按照LZ的需求,后两者最合适
[解决办法]
到底是多线程访问同一服务还是多进程?
多线程的话直接可以用Invoke或者delegate等
多进程的话涉及到windows的消息机制
下面是一段接收端简单示例,基本上就是这样
- C# code
protected override void DefWndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case WM_COPYDATA: //your process break; default: base.DefWndProc(ref m); break; } }
[解决办法]
问题一:开辟内存空间何解?你不是已经有了一个服务进程么?这个服务进程对访问它的其他客户端进程而言,不就是一段可以共享的内存空间么?
问题二:进程间通讯我比较习惯用的是windows Message。至于数据最新,这个你自己设计相关逻辑去更新你服务进程中的数据。
给你一个winMsg例子做参考
Server发送数据
- C# code
private static void YourSendMessage(string strSendingData) { //调用发送消息方法 sendMessage(strSendingData); } const int WM_COPYDATA = 0x004A; //发送消息 [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage( int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam ); //通过窗口标题找到窗口 [DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName); public static void sendMessage(string strSendingMsg) { string winName = ""; //你想要发送的窗口标题 int window_handler = FindWindow(null, @winName); if (window_handler != 0) { byte[] byt = System.Text.Encoding.Default.GetBytes(strSendingMsg); int len = byt.Length; COPYDATASTRUCT cds; cds.dwData = (IntPtr)100; cds.lpdata = strSendingMsg; cds.cbData = len + 1; SendMessage(window_handler, WM_COPYDATA, 0, ref cds); } } public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpdata; }
[解决办法]
下面例子可以直接运行(需要VS2010,因为MemoryMappedFile是.net4才有)。
编译通过后,先运行多个例子,看看互相之间的交互结果。
其中MemoryMappedFile为共享内存,Mutex用来进行同步,ManualResetEvent用来通知有新的更新。
更新通知很初级但基本有效,我有时间再作进一步解释。
- C# code
class Program{ static void Main() { new Program().Run(); } void Run() { ThreadPool.QueueUserWorkItem(this.Observer); string line; while ((line = Console.ReadLine()) != "") { Console.CursorTop = Console.CursorLeft = 0; Console.Write(new string(' ', 80)); Console.CursorTop = Console.CursorLeft = 0; PutString(line); } } List<string> lines = new List<string>(); void DisplayLines() { Console.CursorTop = Console.CursorLeft = 0; Console.WriteLine(Environment.NewLine); Console.ForegroundColor = ConsoleColor.DarkGreen; foreach (string line in lines) { Console.WriteLine(line); } Console.ForegroundColor = ConsoleColor.Gray; Console.CursorTop = Console.CursorLeft = 0; } void Observer(object state) { int lastOffset = sizeof(int); while (true) { notifyEvent.WaitOne(); if (GetStrings(ref lastOffset) == false) { Thread.Sleep(50); } } } void PutString(object state) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(state as string); try { mutex.WaitOne(); using (MemoryMappedViewAccessor accessor = memMap.CreateViewAccessor()) { int offset = accessor.ReadInt32(0); offset = Math.Max(sizeof(int), offset); accessor.Write(offset, (int)bytes.Length); offset += sizeof(int); accessor.WriteArray<byte>(offset, bytes, 0, bytes.Length); offset += bytes.Length; accessor.Write(0, offset); } } finally { mutex.ReleaseMutex(); } notifyEvent.Set(); Thread.Sleep(100); notifyEvent.Reset(); } bool GetStrings(ref int lastOffset) { try { mutex.WaitOne(); using (MemoryMappedViewAccessor accessor = memMap.CreateViewAccessor()) { int newOffset = accessor.ReadInt32(0); if (newOffset <= lastOffset) return false; for (int offset = lastOffset; offset < newOffset; ) { int stringLength = accessor.ReadInt32(offset); offset += sizeof(int); byte[] bytes = new byte[stringLength]; accessor.ReadArray<byte>(offset, bytes, 0, bytes.Length); offset += stringLength; this.lines.Add(Encoding.UTF8.GetString(bytes)); } lastOffset = newOffset; } } finally { mutex.ReleaseMutex(); } DisplayLines(); return true; } Mutex mutex = new Mutex(false, "MyMutex"); MemoryMappedFile memMap = MemoryMappedFile.CreateOrOpen("MyMemoryMap", 64 * 1024); EventWaitHandle notifyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, "MyNotifyEvent");}
[解决办法]
内存映射