首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

怎么实现开辟一块共享内存和多线程访问该内存

2012-08-07 
如何实现开辟一块共享内存和多线程访问该内存?有一个服务进程S,它包含大量的数据,系统中还有另外几个进程,

如何实现开辟一块共享内存和多线程访问该内存?
有一个服务进程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");}
[解决办法]
内存映射

热点排行