2017-2018-1 20155317 IPC
- 共享内存
共享内存主要是通过映射机制实现的。以window系统调用为例子:Windows 下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用 CreateFileMapping 创建命名的内存映射文件对象时,Windows 即在物理内存申请一块指定大小的内存区域,返回文件映射对象的句柄 hMap。为了能够访问这块内存区域必须调用 MapViewOfFile 函数,促使 Windows 将此内存空间映射到进程的地址空间中。当在其他进程访问这块内存区域时,则必须使用OpenFileMapping 函数取得对象句柄 hMap,并调用 MapViewOfFile 函数得到此内存空间的一个映射。这样一来,系统就把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。
#include <iostream> #include <windows.h> #include <string> #include <cstring> using namespace std; int main() { string strMapName("ShareMemory"); // 内存映射对象名称 string strComData("This is common data!"); // 共享内存中的数据 LPVOID pBuffer; // 共享内存指针 // 首先试图打开一个命名的内存映射文件对象 HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, strMapName.c_str()); if (NULL == hMap) { // 打开失败,创建之 hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,strComData.length()+1,strMapName.c_str()); // 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据 pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); strcpy((char*)pBuffer, strComData.c_str()); cout << "写入共享内存数据:" << (char *)pBuffer << endl; } else { // 打开成功,映射对象的一个视图,得到指向共享内存的指针,显示出里面的数据 pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); cout << "读取共享内存数据:" << (char *)pBuffer << endl; } getchar(); // 注意,进程关闭后,所有句柄自动关闭,所以要在这里暂停 // 解除文件映射,关闭内存映射文件对象句柄 ::UnmapViewOfFile(pBuffer); ::CloseHandle(hMap); system("pause"); return 0; }
- 管道
#include<stdio.h> #include<unistd.h> #include<signal.h> #include<stdlib.h> #include<sys/wait.h> int pid1,pid2; int main() { int fd[2]; char outpipe[100],inpipe[100]; while((pid1 = fork()) == -1); if(pid1 == 0) { lockf(fd[1], 1, 0); sprintf(outpipe,"\n child process 1 is sending message!\n"); write(fd[1], outpipe, 50); sleep(5); lockf(fd[1], 0, 0); exit(0); } else { while((pid2 = fork()) == -1); if(pid2 == 0) { lockf(fd[1], 1, 0); sprintf(outpipe,"\n child process 2 is sending message !\n"); write(fd[1], outpipe, 50); sleep(5); lockf(fd[1], 0, 0); exit(0); } else { wait(0); read(fd[0], inpipe, 50); printf("%s\n",inpipe); wait(0); read(fd[0], inpipe, 50); printf("%s\n",inpipe); exit(0); } } }
- FIFO
FIFO与管道类似,它们最大的差别是,FIFO在文件系统中拥有一个名称,并且其打开方式与打开一个普通文件是一样的,这样就能够将FIFO用于非相关进程之间的通信。
#include<sys/types.h> 2.#include<sys/stat.h> 3.#include<errno.h> 4.#include<fcntl.h> 5.#include<stdio.h> 6.#include<stdlib.h> 7.#include<string.h> 8.#define FIFO_SERVER "./myfifo" 9.main(int argc,char** argv) 10.{ 11. int fd; 12. char w_buf[100]; 13. int nwrite; 14. if(fd==-1) 15. if(errno==ENXIO) 16. printf("open error;no reading process\n"); 17. fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0); 18. if(argc==1) 19. printf("Please send something\n"); 20. strcpy(w_buf,argv[1]); 21. if((nwrite=write(fd,w_buf,100))==-1) 22. { 23. if(errno==EAGAIN) 24. printf("The FIFO has not been read yet. Please try later\n"); 25. } 26. else 27. printf("write %s to the FIFO\n",w_buf); 28.}
- 信号
信号实际上是软中断,既然是中断那么信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。 信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
#include <signal.h> #include <sys/types.h> #include <unistd.h> void new_op(int,siginfo_t*,void*); int main(int argc,char**argv) { struct sigaction act; union sigval mysigval; int i; int sig; pid_t pid; char data[10]; mset(data,0,sizeof(data)); for(i=0; i < 5; i++) data[i]=‘2‘; mysigval.sival_ptr=data; sig=atoi(argv[1]); p sid=getpid(); sigemptyset(&act.sa_mask); act.sa_sigaction=new_op;//三参数信号处理函数 act.sa_flags=SA_SIGINFO;//信息传递开关 if(sigaction(sig,&act,NULL) < 0) { printf("install sigal error\n"); } while(1) { sleep(2); printf("wait for the signal\n"); sigqueue(pid,sig,mysigval);//向本进程发送信号,并传递附加信息 } } void new_op(int signum,siginfo_t *info,void *myact)//三参数信号处理函数的实现 { int i; for(i=0; i<10; i++) { printf("%c\n ",(*( (char*)((*info).si_ptr)+i))); } printf("handle signal %d over;",signum); }
- 消息队列
“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。
消息被发送到队列中。“消息队列”是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
“消息队列”是 Microsoft 的消息处理技术,它在任何安装了 Microsoft Windows 的计算机组合中,为任何应用程序提供消息处理和消息队列功能,无论这些计算机是否在同一个网络上或者是否同时联机。
“消息队列网络”是能够相互间来回发送消息的任何一组计算机。网络中的不同计算机在确保消息顺利处理的过程中扮演不同的角色。它们中有些提供路由信息以确定如何发送消息,有些保存整个网络的重要信息,而有些只是发送和接收消息。
“消息队列”安装期间,管理员确定哪些服务器可以互相通信,并设置特定服务器的特殊角色。构成此“消息队列”网络的计算机称为“站点”,它们之间通过“站点链接”相互连接。每个站点链接都有一个关联的“开销”,它由管理员确定,指示了经过此站点链接传递消息的频率。
“消息队列”管理员还在网络中设置一台或多台作为“路由服务器”的计算机。路由服务器查看各站点链接的开销,确定经过多个站点传递消息的最快和最有效的方法,以此决定如何传递消息。
#include < stdio.h > #include < stdlib.h > #include < ctype.h > #include < sys / ipc.h > #include < sys / types.h > #include < sys / msg.h > #define MAX_SEND_SIZE 80 struct mymsgbuf { long mtype; char mtext[MAX_SEND_SIZE]; } ; void send_message( int qid, struct mymsgbuf * qbuf, long type, char * text); void read_message( int qid, struct mymsgbuf * qbuf, long type); void remove_queue( int qid); void change_queue_mode( int qid, char * mode); void usage( void ); int main( int argc, char * argv[]) { key_t key; int msgqueue_id; struct mymsgbuf qbuf; if ( 1 == argc) usage(); key = ftok( " . " , ‘ m ‘ ); if ((msgqueue_id = msgget(key,IPC_CREAT | 0660 )) ==- 1 ) { perror( " msgget " ); exit( 1 ); } switch (tolower(argv[ 1 ][ 0 ])) { case ‘ s ‘ : send_message(msgqueue_id,( struct mymsgbuf * ) & qbuf, atol(argv[ 2 ]),argv[ 3 ]); break ; case ‘ r ‘ : read_message(msgqueue_id, & qbuf,atol(argv[ 2 ])); break ; case ‘ d ‘ : remove_queue(msgqueue_id); break ; case ‘ m ‘ : change_queue_mode(msgqueue_id,argv[ 2 ]); break ; default : usage(); } return 0 ; } void send_message( int qid, struct mymsgbuf * qbuf, long type, char * text) { printf( " send a message /n " ); qbuf -> mtype = type; strcpy(qbuf -> mtext,text); if ((msgsnd(qid,( struct msgbuf * )qbuf,strlen(qbuf -> mtext) + 1 , 0 )) ==- 1 ) { perror( " msgsnd " ); exit( 1 ); } } void read_message( int qid, struct mymsgbuf * qbuf, long type) { printf( " reading a message./n " ); qbuf -> mtype = type; msgrcv(qid,( struct msgbuf * )qbuf,MAX_SEND_SIZE,type, 0 ); printf( " Type: %1d Text: %s/n " ,qbuf -> mtype,qbuf -> mtext); } void remove_queue( int qid) { msgctl(qid,IPC_RMID, 0 ); } void change_queue_mode( int qid, char * mode) { struct msqid_ds myqueue_ds; msgctl(qid,IPC_STAT, & myqueue_ds); sscanf(mode, " %ho " , & myqueue_ds.msg_perm.mode); msgctl(qid,IPC_SET, & myqueue_ds); } void usage( void ) { fprintf(stderr, " msgtool -A utility for tinkering with msg queue/n " ); fprintf(stderr, " /nUSAGE:msgtool (s)end <type> <messagetext>/n " ); fprintf(stderr, " (r)ecv<type>/n " ); fprintf(stderr, " (d)elete/n " ); fprintf(stderr, " (m)ode<octal mode>/n " ); exit( 1 ); }