C# 进程间通信(共享内存)

原文:C# 进程间通信(共享内存)

进程间通信的方式有很多,常用的方式有:

1.共享内存(内存映射文件,共享内存DLL)。

2.命名管道和匿名管道。

3.发送消息 

本文是记录共享内存的方式进行进程间通信,首先要建立一个进程间共享的内存地址,创建好共享内存地址后,一个进程向地址中写入数据,另外的进程从地址中读取数据。

在数据的读写的过程中要进行进程间的同步。

进程间数据同步可以有以下的方式

1. 互斥量Mutex

2. 信号量Semaphore

3. 事件Event 

本文中进程间的同步采用 信号量Semaphore的方式同步思想类似于操作系统中生产者和消费者问题的处理方式。

在A进程中创建共享内存,并开启一个线程用来读取B进程向共享内存中写入的数据,定义两个信号量进行读写互斥同步 

A进程中的程序代码

 using System;

using System.Collections.Generic;
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.Collections.Generic;
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++;
                }
            }
        }

   }
}

 

时间: 2024-10-26 13:43:22

C# 进程间通信(共享内存)的相关文章

win32下进程间通信(共享内存)实例分析_C 语言

一.概述 很多情况下在Windows程序中,各个进程之间往往需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换. 进程间通讯(即:同机通讯)和数据交换有多种方式:消息.共享内存.匿名(命名)管道.邮槽.Windows套接字等多种技术."共享内存"(shared memory)可以定义为对一个以上的进程是可见的内存或存在于多个进程的虚拟地址空间.例如:如果两个进程使用相同的DLL,只把DLL的代码

Linux环境进程间通信共享内存

由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以. 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件.实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域.而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存

Linux进程间通信学习:如何使用共享内存

下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 特别提醒:共

进程间通信之-共享内存Shared Memory--linux内核剖析(十一)

共享内存 共享内存是进程间通信中最简单的方式之一. 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区. 共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针.当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改. 关于共享内存 当一个程序加载进内存后,它就被分成叫作页的块. 通信将存在内存的两个页之间或者两个独立的进程之间. 总之,当一个程序想和另外一个程序通信的时候,那内存将会为这两个程序生成一块公共的

Qt之进程间通信(共享内存)

简述 上一节中,我们分享下如何利用Windows消息机制来进行不同进程间的通信.但是有很多局限性,比如:不能跨平台,而且必须两个进程同时存在才可以,要么进程A发了消息谁接收呢? 下面我们来分享另外一种跨平台的进行间通信的方式-Shared Memory(共享内存). Qt提供的基于共享内存的IPC有QSharedMemory类和QSystemSemaphore类,QSharedMemory可以访问共享内存区域,以及多线程和进程的共享内存区域.而QSystemSemaphore类用于访问系统共享资

C++使用共享内存实现进程间通信

文件映射是一种实现进程间单向或双向通信的机制.它允许两个或多个本地进程间相互通信.为了共享文件或内存,所有的进程必须使用相同的文件映射的名字或是句柄. 为了实现共享文件,第一个进程先调用Createhttp://www.aliyun.com/zixun/aggregation/19352.html">File方法.接下来调用CreateFileMapping方法来创建一个文件映射对象.并为文件映射指明一个句柄和名称.由于事件,信号,互斥对象和文件映射等这些内核对象都共享同一个名字空间,所以

SYSTEM V标准的共享内存用于进程间通信的权限管理示例

  输出同现SEGMENTATION FAULT是因为试图写操作,这是因为将虚拟内存挂载为了READ ONLY方式导致的权限不够. 1 #include <sys/shm.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <sys/ipc.h> 6 #include <string.h> 7 8 int main(int arg

PHP 直接在共享内存中存储数据集

共享内存是一种在相同机器中的应用程序之间交换数据的有效方式.一个进程可创建一个可供其他进程访问的内存段,只要它分配了正确的权限.每个内存段拥有一个惟一的 ID(称为 shmid),这个 ID 指向一个物理内存区域,其他进程可在该区域操作它.创建并提供了合适的权限之后,同一台机器中的其他进程就可以操作这些内存段:读取.写入和删除. 这表明使用 C 语言编写的应用程序可与使用其他语言(比如 Java 或 PHP)编写的应用程序共享信息.它们都可以共享信息,只要它们可访问和理解该信息.共享内存在针对大

Linux下C编程:共享内存通信实例

共享内存是LUNIX 系统中最底层的通信机制,也是最快速的通信机制.共享内存通过两个或多个进程共享同一块内存区域来实现进程间的通信.通常是由一个进程创建一块共享 内存区域,然后多个进程可以对其进行访问,一个进程将要传出的数据存放到共享内存中,另一个或多个进程则直接从共享内存中读取数据.因此这种通信方式是最高效的进程间通信方式.但实际的问题在于,当两个或多个进程使用共享内存进行通信时,同步问题的解决显得尤为重要,否则就会造成因不同进程同时读写一块共享内存中的数据而发生混乱.在通常的情况下,通过使用