网站设计制作中心,大连哪家装修公司最好,吉首公司网站找谁做,怎样用网站做单笔外贸进程间通信目的
数据传输#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享#xff1a;多个进程之间共享同样的资源。 通知事件#xff1a;一个进程需要向另一个或一组进程发送消息#xff0c;通知它#xff08;它们#xff09;发生了某种事件#xff08;如…进程间通信目的
数据传输一个进程需要将它的数据发送给另一个进程 资源共享多个进程之间共享同样的资源。 通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。 进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变。
通信背景
1.由于进程是具有独立性的进程想交互数据成本会非常高。但是有些情况下需要多进程处理一件事情。 2.进程独立并不是彻底独立有时候我们需要双方能够进行一定程度的信息交互。
我们要学的进程间通信不是告诉我们如何通信是他们两个如何先看到同一份资源。文件内存块…等方式
共享内存实现进程间通信的原理
共享内存实际是操作系统在实际物理内存中开辟的一段内存。
共享内存实现进程间通信是操作系统在实际物理内存开辟一块空间一个进程在自己的页表中将该空间和进程地址空间上的共享区的一块地址空间形成映射关系。另外一进程在页表上将同一块物理空间和该进程地址空间上的共享区的一块地址空间形成映射关系。 当一个进程往该空间写入内容时另外一进程访问该空间会得到写入的值即实现了进程间的通信。
要实现进程间通信需要两个进程看到同一块空间系统开辟的共享内存就是两个进程看到的同一资源。
注意共享内存实现进程间通信是进程间通信最快的。 如何使⽤
要使⽤⼀块共享内存进程必须先分配它。其他需要访问这个共享内存块的每⼀个进程都必须将这个共享绑定attach到⾃⼰的地址空间中系统维护⼀个对该内存的引⽤计数器通过ipcs -s 命令可查看有⼏个进程在使⽤该共享内存块。当通信完毕后所有进程从共享内存块脱离由⼀个进程释放该共享内存块。要注意的是所有⽤户申请的共享内存块最终⼤⼩都必须是向上取整为系统页⾯⼤⼩的整数倍。在Linux系统中内存页⾯⼤⼩默认是4KB。
注意当⼀个进程创建⼀块共享内存后该进程在主动去释放该共享内存之前被kill掉时只会使该进程脱离detach该共享内存块⽽不会释放该共享内存块这时候可以使⽤命名ipcrm -m 去释放该资源。
相关函数
1、shmget
#include sys/ipc.h
#include sys/shm.h
int shmget(key_t key, size_t size, int shmflg);
函数说明得到⼀个共享内存标识符或创建⼀个共享内存对象并返回共享内存标识符。 参数 key ftok函数返回的I PC键值 size ⼤于0的整数新建的共享内存⼤⼩以字节为单位获取已存在的共享内存块标识符时该参数为0, shmflg IPC_CREAT||IPC_EXCL 执⾏成功保证返回⼀个新的共享内存标识符附加参数指定IPC对象存储权限如|0666 返回值成功返回共享内存的标识符出错返回-1并设置error错误位。
key共享内存的唯一值这个参数需要由用户提供。 共享内存要被管理 - struct shmid_ds - struct ipc_perm - key(shmget)(共享内存唯一值)
1. 为什么key值需要由用户提供 进程间通信的前提是先让不同的进程看到同一份资源。如果由操作系统提供创建共享内存的进程可以知道key值但是使用共享内存的进程无法获取。所以key值必须由用户获取然后在使用时标定key值则能让使用共享内存的进程获取到。
共享内存在内核中让不同的进程看到同一份共享内存做法是让他们拥有同一个key即可。
匿名管道 -- 约定好使用同一个文件 共享内存 -- 约定好使用同一个唯一key
2.为什么key值要有唯一性 操作系统中可能有很多个共享内存在被使用所以我们就需要用一个唯一值来标识每一个共享内存。
3. 那么如何保证key值唯一性呢 生成唯一key值函数ftok函数。
key_t ftok(const char *pathname, int proj_id); 将文件路径和一个项目标识符转化为唯一key值。
返回值一个整数创建成功返回一个合法的共享内存标识符。失败返回 -1。 2、shmat
#include sys/types.h
#include sys/shm.h
void *shmat(int shmid, const void shmaddr, int shmflg);
函数说明连接共享内存标识符为shmid的共享内存连接成功后把共享内存区对象映射到调⽤进程的地址空间 参数 shmid 共享内存标识符 shmaddr 指定共享内存出现在进程内存地址的什么位置通常指定为NULL让内核⾃⼰选择⼀个合适的地址位置 shmflg SHM_RDONLY 为只读模式其他参数为读写模式 返回值成功返回附加好的共享内存地址出错返回-1并设置error错误位
3、shmdt
#include sys/types.h
#include sys/shm.h
void *shmdt(const void* shmaddr);
函数说明与shmat函数相反是⽤来断开与共享内存附加点的地址禁⽌本进程访问此⽚共享内存需要注意的是该函数并不删除 所指定的共享内存区⽽是将之前⽤shmat函数连接好的共享内存区脱离⽬前的进程 参数shmddr 连接共享内存的起始地址 返回值成功返回0出错返回-1并设置error。
4、shmctl
#include sys/types.h
#Include sys/shm.h
int shmctl(int shmid, int cmd, struct shmid_ds* buf);
函数说明控制共享内存块 参数 shmid共享内存标识符 cmd IPC_STAT得到共享内存的状态把共享内存的shmid_ds结构赋值到buf所指向的buf中 IPC_SET改变共享内存的状态把buf所指向的shmid_ds结构中的uid、gid、mode赋值到共享内存的shmid_ds结构内 IPC_RMID删除这块共享内存 buf共享内存管理结构体 返回值成功返回0出错返回-1并设置error错误位。
代码演⽰
父子进程通信范例
shm.c源代码如下
#include stdio.h
#include unistd.h
#include string.h
#include sys/ipc.h
#include sys/shm.h
#include error.h
#define SIZE 1024
int main()
{int shmid ;char *shmaddr ;struct shmid_ds buf ;int flag 0 ;int pid ;shmid shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;if ( shmid 0 ){perror(get shm ipc_id error) ;return -1 ;}pid fork() ;if ( pid 0 ){shmaddr (char *)shmat( shmid, NULL, 0 ) ;if ( (int)shmaddr -1 ){perror(shmat addr error) ;return -1 ;}strcpy( shmaddr, Hi, I am child process!\n) ;shmdt( shmaddr ) ;return 0;} else if ( pid 0) {sleep(3 ) ;flag shmctl( shmid, IPC_STAT, buf) ;if ( flag -1 ){perror(shmctl shm error) ;return -1 ;}printf(shm_segsz %d bytes\n, buf.shm_segsz ) ;printf(parent pid%d, shm_cpid %d \n, getpid(), buf.shm_cpid ) ;printf(chlid pid%d, shm_lpid %d \n,pid , buf.shm_lpid ) ;shmaddr (char *) shmat(shmid, NULL, 0 ) ;if ( (int)shmaddr -1 ){perror(shmat addr error) ;return -1 ;}printf(%s, shmaddr) ;shmdt( shmaddr ) ;shmctl(shmid, IPC_RMID, NULL) ;}else{perror(fork error) ;shmctl(shmid, IPC_RMID, NULL) ;}return 0 ;
}
编译 gcc shm.c –o shm。 执行 ./shm执行结果如下 shm_segsz 1024 bytes shm_cpid 9503 shm_lpid 9504 Hi, I am child process! ⾸先先来讲⼀下fork之后发⽣了什么事情。 由fork创建的新进程被称为⼦进程child process。该函数被调⽤⼀次但返回两次。两次返回的区别是⼦进程的返回值是0⽽⽗进程的返回值则是新进程⼦进程的进程 id。将⼦进程id返回给⽗进程的理由是因为⼀个进程的⼦进程可以多于⼀个没有⼀个函数使⼀个进程可以获得其所有⼦进程的进程id。对⼦进程来说之所以fork返回0给它是因为它随时可以调⽤getpid()来获取⾃⼰的pid也可以调⽤getppid()来获取⽗进程的id。(进程id 0总是由交换进程使⽤所以⼀个⼦进程的进程id不可能为0 )。 fork之后操作系统会复制⼀个与⽗进程完全相同的⼦进程虽说是⽗⼦关系但是在操作系统看来他们更像兄弟关系这2个进程共享代码空间但是数据空间是互相独⽴的⼦进程数据空间中的内容是⽗进程的完整拷贝指令指针也完全相同⼦进程拥有⽗进程当前运⾏到的位置两进程的程序计数器pc值相同也就是说⼦进程是从fork返回处开始执⾏的但有⼀点不同如果fork成功⼦进程中fork的返回值是0⽗进程中fork的返回值是⼦进程的进程号如果fork不成功⽗进程会返回错误。 可以这样想象2个进程⼀直同时运⾏⽽且步调⼀致在fork之后他们分别作不同的⼯作也就是分岔了。这也是fork为什么叫fork的原因⾄于哪⼀个最先运⾏可能与操作系统调度算法有关⽽且这个问题在实际应⽤中并不重要如果需要⽗⼦进程协同可以通过原语的办法解决。 多进程读写范例
多进程读写即一个进程写共享内存一个或多个进程读共享内存。下面的例子实现的是一个进程写共享内存一个进程读共享内存。 1下面程序实现了创建共享内存并写入消息。 shmwrite.c源代码如下
#include stdio.h
#include sys/ipc.h
#include sys/shm.h
#include sys/types.h
#include unistd.h
#include string.h
typedef struct{char name[8];int age;
} people;
int main(int argc, char** argv)
{int shm_id,i;key_t key;char temp[8];people *p_map;char pathname[30] ;strcpy(pathname,/tmp) ;key ftok(pathname,0x03);if(key-1){perror(ftok error);return -1;}printf(key%d\n,key) ;shm_idshmget(key,4096,IPC_CREAT|IPC_EXCL|0600); if(shm_id-1){perror(shmget error);return -1;}printf(shm_id%d\n, shm_id) ;p_map(people*)shmat(shm_id,NULL,0);memset(temp, 0x00, sizeof(temp)) ;strcpy(temp,test) ;temp[4]0;for(i 0;i3;i){temp[4]1;strncpy((p_mapi)-name,temp,5);(p_mapi)-age0i;}shmdt(p_map) ;return 0 ;
}
2下面程序实现从共享内存读消息。 shmread.c源代码如下
#include stdio.h
#include string.h
#include sys/ipc.h
#include sys/shm.h
#include sys/types.h
#include unistd.h
typedef struct{char name[8];int age;
} people;
int main(int argc, char** argv)
{int shm_id,i;key_t key;people *p_map;char pathname[30] ;strcpy(pathname,/tmp) ;key ftok(pathname,0x03);if(key -1){perror(ftok error);return -1;}printf(key%d\n, key) ;shm_id shmget(key,0, 0); if(shm_id -1){perror(shmget error);return -1;}printf(shm_id%d\n, shm_id) ;p_map (people*)shmat(shm_id,NULL,0);for(i 0;i3;i){printf( name:%s\n,(*(p_mapi)).name );printf( age %d\n,(*(p_mapi)).age );}if(shmdt(p_map) -1){perror(detach error);return -1;}return 0 ;
}
3编译与执行 ①编译gcc shmwrite.c -o shmwrite。 ②执行./shmwrite执行结果如下 key50453281 shm_id688137 ③编译gcc shmread.c -o shmread。 ④执行./shmread执行结果如下 key50453281 shm_id688137 name:test1 age 0 name:test2 age 1 name:test3 age 2 ⑤再执行./shmwrite执行结果如下 key50453281 shmget error: File exists ⑥使用ipcrm -m 688137删除此共享内存。