系统编程--进程间通信
这篇进程间通信,包含的内容比较多,包括最基本的pipe和fifo,XSI(System V)标准和POSIX标准的消息队列、信号量、共享内存,同时也有介绍mmap映射的相关内容,算是一个大总结,参考比较多的资料。
管道
管道是UNIX系统IPC的最古老形式,在shell下的表现形式为管道线。每当在管道线中输入一个由shell执行的命令序列时,shell为每一条命令单独创建一进程,然后将前一条命令进程的标准输出用管道与后一条命令的标准输入相连接。管道有两个主要局限:
1).管道是半双工的,即数据只能在一个方向上流动。
2).管道只能在具有公共祖先的进程之间使用。
管道是由调用pipe函数而创建的.
#include <unistd.h> int pipe(int filedes[2]); //成功返回0,错误返回-1。
经由参数filedes返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。单个进程中的管道几乎没有任何用处。通常,调用pipe的进程接着调用fork,这样就创建了从父进程到子进程或反之的IPC通道。下面显示了这种情况
#include <unistd.h> #include <stdio.h> int main(){ int filedes[2]; char buf[80]; pid_t pid; pipe( filedes ); pid=fork(); if (pid > 0) { printf( "This is in the father process,here write a string to the pipe.\n" ); char s[] = "Hello world , this is write by pipe.\n"; write( filedes[1], s, sizeof(s) ); close( filedes[0] ); close( filedes[1] ); } else if(pid == 0) { printf( "This is in the child process,here read a string from the pipe.\n" ); read( filedes[0], buf, sizeof(buf) ); printf( "%s\n", buf ); close( filedes[0] ); close( filedes[1] ); } waitpid( pid, NULL, 0 ); return 0; }
#include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "./my_fifo" #define BUFFER_SIZE 20 int main() { int pipe_fd; int res; int open_mode = O_RDONLY; char buffer[BUFFER_SIZE + 1]; memset(buffer, '\0', sizeof(buffer)); printf("Process %d opeining FIFO O_RDONLY\n", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %d\n", getpid(), pipe_fd); if (pipe_fd != -1) { do{ res = read(pipe_fd, buffer, BUFFER_SIZE); printf("%s\n",buffer); }while(res > 0); close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished \n", getpid()); exit(EXIT_SUCCESS); }
write
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "./my_fifo" #define BUFFER_SIZE 20 int main() { int pipe_fd; int res; int open_mode = O_WRONLY; char buffer[BUFFER_SIZE + 1]; if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777); if (res != 0) { fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO O_WRONLY\n", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %d\n", getpid(), pipe_fd); sleep(2); if (pipe_fd != -1) { while (1) { memset(buffer,0,sizeof(buffer)); scanf("%s",buffer); res = write(pipe_fd, buffer, sizeof(buffer)); if (res == -1) { fprintf(stderr, "Write error on pipe\n"); exit(EXIT_FAILURE); } } close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finish\n", getpid()); exit(EXIT_SUCCESS); }
XSI IPC
#include <sys/ipc.h> key_t ftok(const char *path, int id); //成功返回关键字,失败返回(key_t)-1。
path参数必须指向一个已有的文件。在产生关键字时只有id的低8位被使用。
struct ipc_perm { uid_t uid; /* owner's effective user id */ gid_t gid; /* owner's effective group id */ uid_t cuid; /* creator's effective user id */ gid_t cgid; /* creator's effective group id */ mode_t mode; /* access modes */ ... };
可以调用msgctl、semctl或shmctl函数修改uid、gid和mode字段。为了改变这些值,调用进程必须是IPC结构的创建者或超级用户。对于任何IPC结构不存在执行权限。
消息队列是消息的链接表,存放在内核中并由消息队列标识符标识.。我们将称消息队列为“队列”,其标识符为“队列ID”
1).每个队列都有一个msqid_ds结构与其相关。此结构规定了队列的当前状态。
struct msqid_ds { struct ipc_perm msg_perm; /* see Section 15.6.2 */ msgqnum_t msg_qnum; /* # of messages on queue */ msglen_t msg_qbytes; /* max # of bytes on queue */ pid_t msg_lspid; /* pid of last msgsnd() */ pid_t msg_lrpid; /* pid of last msgrcv() */ time_t msg_stime; /* last-msgsnd() time */ time_t msg_rtime; /* last-msgrcv() time */ time_t msg_ctime; /* last-change time */ ... };
#include <sys/msg.h> int msgget (key_t key, int flag); //成功返回消息队列ID。错误返回-1。
#include <sys/msg.h> int msgctl (int msqid, int cmd, struct msqid_ds *buf); //成功返回0,错误返回-1。
cmd参数指定对于由msqid规定的队列要执行的命令
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
#include <sys/msg.h> int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag); //成功返回0,错误返回-1。
#include <sys/msg.h> ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag); //成功返回消息的数据部分的尺寸,错误返回-1。
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <sys/msg.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define BUFFSIZ 512 struct msg_st{ long int msg_type; char text[BUFFSIZ]; }; int main() { int running = 1; int msgid = -1; struct msg_st data; long int msgtype = 0; //注意1 //建立消息队列 msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if(msgid == -1) { fprintf(stderr, "msgget failed with error: %d\n", errno); exit(EXIT_FAILURE); } //从队列中获取消息,直到遇到end消息为止 while(running) { if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1) { fprintf(stderr, "msgrcv failed with errno: %d\n", errno); exit(EXIT_FAILURE); } printf("You wrote: %s\n",data.text); //遇到end结束 if(strncmp(data.text, "end", 3) == 0) running = 0; } //删除消息队列 if(msgctl(msgid, IPC_RMID, 0) == -1) { fprintf(stderr, "msgctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
发送
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/msg.h> #include <errno.h> #define MAX_TEXT 512 struct msg_st { long int msg_type; char text[MAX_TEXT]; }; int main() { int running = 1; struct msg_st data; char buffer[BUFSIZ]; int msgid = -1; //建立消息队列 msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if(msgid == -1) { fprintf(stderr, "msgget failed with error: %d\n", errno); exit(EXIT_FAILURE); } //向消息队列中写消息,直到写入end while(running) { //输入数据 printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); data.msg_type = 1; //注意2 strcpy(data.text, buffer); //向队列发送数据 if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1) { fprintf(stderr, "msgsnd failed\n"); exit(EXIT_FAILURE); } //输入end结束输入 if(strncmp(buffer, "end", 3) == 0) running = 0; sleep(1); } exit(EXIT_SUCCESS); }
XSI--信号量
struct semid_ds { struct ipc_perm sem_perm; /* see Section 15.6.2 */ unsigned short sem_nsems; /* # of semaphores in set */ time_t sem_otime; /* last-semop() time */ time_t sem_ctime; /* last-change time */ ... };
struct { unsigned short semval; /* semaphore value, always >= 0 */ pid_t sempid; /* pid for last operation */ unsigned short semncnt; /* # processes awaiting semval>curval */ unsigned short semzcnt; /* # processes awaiting semval==0 */ };
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/sem.h> union semun { int val; struct semid_ds *buf; unsigned short *arry; }; static int sem_id = 0; static int set_semvalue(); static void del_semvalue(); static int semaphore_p(); static int semaphore_v(); int main(int argc, char *argv[]) { char message = 'X'; int i = 0; //创建信号量 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT); if(argc > 1) { //程序第一次被调用,初始化信号量 if(!set_semvalue()) { fprintf(stderr, "Failed to initialize semaphore\n"); exit(EXIT_FAILURE); } //设置要输出到屏幕中的信息,即其参数的第一个字符 message = argv[1][0]; sleep(2); } for(i = 0; i < 10; ++i) { //进入临界区 if(!semaphore_p()) exit(EXIT_FAILURE); //向屏幕中输出数据 printf("%c", message); //清理缓冲区,然后休眠随机时间 fflush(stdout); sleep(rand() % 3); //离开临界区前再一次向屏幕输出数据 printf("%c", message); fflush(stdout); //离开临界区,休眠随机时间后继续循环 if(!semaphore_v()) exit(EXIT_FAILURE); sleep(rand() % 2); } sleep(10); printf("\n%d - finished\n", getpid()); if(argc > 1) { //如果程序是第一次被调用,则在退出前删除信号量 sleep(3); del_semvalue(); } exit(EXIT_SUCCESS); } static int set_semvalue() { //用于初始化信号量,在使用信号量前必须这样做 union semun sem_union; sem_union.val = 1; if(semctl(sem_id, 0, SETVAL, sem_union) == -1) return 0; return 1; } static void del_semvalue() { //删除信号量 union semun sem_union; if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) fprintf(stderr, "Failed to delete semaphore\n"); } static int semaphore_p() { //对信号量做减1操作,即等待P(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1;//P() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_p failed\n"); return 0; } return 1; } static int semaphore_v() { //这是一个释放操作,它使信号量变为可用,即发送信号V(sv) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1;//V() sem_b.sem_flg = SEM_UNDO; if(semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_v failed\n"); return 0; } return 1; }
struct shmid_ds { struct ipc_perm shm_perm; /* see Section 15.6.2 */ size_t shm_segsz; /* size of segment in bytes */ pid_t shm_lpid; /* pid of last shmop() */ pid_t shm_cpid; /* pid of creator */ shmatt_t shm_nattch; /* number of current attaches */ time_t shm_atime; /* last-attach time */ time_t shm_dtime; /* last-detach time */ time_t shm_ctime; /* last-change time */ ... };
#include <unistd.h> #include <error.h> #include <sys/types.h> #include <sys/shm.h> #define SHM_SIZE 1024 #define SHM_MODE (SHM_R|SHM_W|IPC_CREAT) int main(){ void *shm=NULL; int *shared=NULL; int shmid=shmget((key_t)23,sizeof(int),SHM_MODE); if(shmid==-1){ perror("shmget error"); } shm=shmat(shmid,(void*)0,0); if(shm==(void*)-1){ perror("shmat error"); } shared=(int *)shm; int i=0; while(1){ sleep(1); *shared=i++; } if(shmdt(shm)==-1){ perror("shmdt error"); } return 0;
POSIX IPC
使用gcc编译时,需要加上 -lrt
POSIX IPC名字标准:
#include <mqueue.h> mqd_t mq_open(const char *name, int oflag, /* mode_t mode, struct mq_attr *attr */); //成功返回消息队列描述符,失败返回-1 mqd_t mq_close(mqd_t mqdes); mqd_t mq_unlink(const char *name); //成功返回0,失败返回-1
POSIX标准规定消息队列属性mq_attr必须要含有以下四个内容: long mq_flags //消息队列的标志:0或O_NONBLOCK,用来表示是否阻塞 long mq_maxmsg //消息队列的最大消息数 long mq_msgsize //消息队列中每个消息的最大字节数 long mq_curmsgs //消息队列中当前的消息数目 mq_attr结构的定义如下: #include <mqueue.h> mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr); mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr); //成功返回0,失败返回-1
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <mqueue.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> int main() { mqd_t mqid; mqid=mq_open("/myqueue",O_RDWR|O_CREAT,0666,NULL); if(mqid<0){ perror("open error"); exit(mqid); } struct mq_attr mqattr; if(mq_getattr(mqid,&mqattr)<0){ perror("get attr error"); exit(-1); } printf("mq_flags: %ld\n",mqattr.mq_flags); printf("mq_maxmsg: %ld\n",mqattr.mq_maxmsg); printf("mq_msgsize: %ld\n",mqattr.mq_msgsize); printf("mq_curmsgs: %ld\n",mqattr.mq_curmsgs); return 0; }
消息队列使用
#include <mqueue.h> mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); //成功返回0,出错返回-1 mqd_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); //成功返回接收到消息的字节数,出错返回-1 #ifdef __USE_XOPEN2K mqd_t mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout); mqd_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); #endif
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <mqueue.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> int main() { mqd_t mqid; mqid=mq_open("/myqueue",O_RDWR|O_CREAT,0666,NULL); if(mqid<0){ perror("open error"); exit(mqid); } struct mq_attr mqattr; if(mq_getattr(mqid,&mqattr)<0){ perror("get attr error"); exit(-1); } int bufsize=mqattr.mq_msgsize; char *buf=(char *)malloc(sizeof(char)*bufsize); int prio=10; int running=1; while(running){ //输入数据 printf("Enter some text: "); fgets(buf, bufsize, stdin); //向队列发送数据 if(mq_send(mqid, buf, bufsize, prio) <0) { fprintf(stderr, "msgsnd failed\n"); exit(EXIT_FAILURE); } //输入end结束输入 if(strncmp(buf, "end", 3) == 0) running = 0; sleep(1); prio++; } free(buf); mq_close(mqid); return 0; }
读测试
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <mqueue.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> int main() { mqd_t mqid; mqid=mq_open("/myqueue",O_RDWR|O_CREAT,0666,NULL); if(mqid<0){ perror("open error"); exit(mqid); } struct mq_attr mqattr; if(mq_getattr(mqid,&mqattr)<0){ perror("get attr error"); exit(-1); } int bufsize=mqattr.mq_msgsize; char *buf=(char *)malloc(sizeof(char)*bufsize); int prio=10; int running=1; while(running){ if(mq_receive(mqid, buf, bufsize, NULL) <0) { fprintf(stderr, "msgsnd failed\n"); exit(EXIT_FAILURE); } printf("rec: %s\n",buf); //输入end结束输入 if(strncmp(buf, "end", 3) == 0) running = 0; } free(buf); mq_close(mqid); return 0; }
POSIX--信号量
- 二值信号量:信号量的值只有0和1,这和互斥量很类型,若资源被锁住,信号量的值为0,若资源可用,则信号量的值为1;
- 计数信号量:信号量的值在0到一个大于1的限制值(POSIX指出系统的最大限制值至少要为32767)。该计数表示可用的资源的个数。
- 互斥量必须由给它上锁的线程解锁。而信号量不需要由等待它的线程进行挂出,可以在其他进程进行挂出操作。
- 互斥量要么被锁住,要么是解开状态,只有这两种状态。而信号量的值可以支持多个进程成功进行wait操作。
- 信号量的挂出操作总是被记住,因为信号量有一个计数值,挂出操作总会将该计数值加1,然而当向条件变量发送一个信号时,如果没有线程等待在条件变量,那么该信号会丢失。
#include <semaphore.h> sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); //成功返回信号量指针,失败返回SEM_FAILED
#include <semaphore.h> int sem_close(sem_t *sem); int sem_unlink(const char *name); //成功返回0,失败返回-1
信号量的P操作 #include <semaphore.h> int sem_wait (sem_t *sem); #ifdef __USE_XOPEN2K int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); #endif int sem_trywait (sem_t * sem); //成功返回0,失败返回-1
信号量的V操作 #include <semaphore.h> int sem_post(sem_t *sem); //成功返回0,失败返回-1
获取当前信号量的值 #include <semaphore.h> int sem_getvalue(sem_t *sem, int *sval); //成功返回0,失败返回-1
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <semaphore.h> #include <signal.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define SEM1_NAME "/mysem1" #define SEM2_NAME "/mysem2" sem_t *pSem1; sem_t *pSem2; int stopflag=0; int val1,val2; static void sigAction(int signo){ if(signo==SIGINT) stopflag=1; } void threadfn1(){ while(stopflag!=1){ sem_wait(pSem2); sleep(1); printf("This is thread 1\n"); if(sem_getvalue(pSem1,&val1)<0) perror("get sem val err"); if(sem_getvalue(pSem2,&val2)<0) perror("get sem val err"); printf("val1= %d\tval2= %d\n",val1,val2); sem_post(pSem1); } } void threadfn2(){ while(stopflag!=1){ sem_wait(pSem1); sleep(1); printf("This is thread 2\n"); if(sem_getvalue(pSem1,&val1)<0) perror("get sem val err"); if(sem_getvalue(pSem2,&val2)<0) perror("get sem val err"); printf("val1= %d\tval2= %d\n",val1,val2); sem_post(pSem2); } } int main(){ if(signal(SIGINT,sigAction)==SIG_ERR) perror("catch SIGINT err"); pSem1=sem_open(SEM1_NAME,O_CREAT,0666,1); pSem2=sem_open(SEM2_NAME,O_CREAT,0666,1); pthread_t tid1,tid2; pthread_create(&tid1,NULL,&threadfn1,NULL); pthread_create(&tid2,NULL,&threadfn2,NULL); sleep(2); pthread_join(tid1,NULL); pthread_join(tid2,NULL); sem_close(pSem1); sem_unlink(SEM1_NAME); sem_close(pSem2); sem_unlink(SEM2_NAME); return 0; }
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); //若出错则返回-1 int sem_destroy(sem_t *sem); //成功返回0,失败返回-1
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <semaphore.h> #include <signal.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> sem_t pSem1; sem_t pSem2; int stopflag=0; int val1,val2; static void sigAction(int signo){ if(signo==SIGINT) stopflag=1; } void threadfn1(){ while(stopflag!=1){ sem_wait(&pSem2); sleep(1); printf("This is thread 1\n"); if(sem_getvalue(&pSem1,&val1)<0) perror("get sem val err"); if(sem_getvalue(&pSem2,&val2)<0) perror("get sem val err"); printf("val1= %d\tval2= %d\n",val1,val2); sem_post(&pSem1); } } void threadfn2(){ while(stopflag!=1){ sem_wait(&pSem1); sleep(1); printf("This is thread 2\n"); if(sem_getvalue(&pSem1,&val1)<0) perror("get sem val err"); if(sem_getvalue(&pSem2,&val2)<0) perror("get sem val err"); printf("val1= %d\tval2= %d\n",val1,val2); sem_post(&pSem2); } } int main(){ if(signal(SIGINT,sigAction)==SIG_ERR) perror("catch SIGINT err"); sem_init(&pSem1,1,1); sem_init(&pSem2,1,1); pthread_t tid1,tid2; pthread_create(&tid1,NULL,&threadfn1,NULL); pthread_create(&tid2,NULL,&threadfn2,NULL); sleep(2); pthread_join(tid1,NULL); pthread_join(tid2,NULL); sem_destroy(&pSem1); sem_destroy(&pSem2); return 0; }
- 如果无名信号量是在单个进程内部的数据空间中,即信号量只能在进程内部的各个线程间共享,那么信号量是随进程的持续性,当进程终止时它也就消失了。
- 如果无名信号量位于不同进程的共享内存区,因此只要该共享内存区仍然存在,该信号量就会一直存在。所以此时无名信号量是随内核的持续性。
POSIX--共享内存
- 对普通文件提供内存映射I/O,可以提供无亲缘进程间的通信;
- 提供匿名内存映射,以供亲缘进程间进行通信。
- 对shm_open创建的POSIX共享内存区对象进程内存映射,以供无亲缘进程间进行通信。
#include <sys/mman.h> void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset); //成功返回映射到进程地址空间的起始地址,失败返回MAP_FAILED
- PROT_READ:数据可读;
- PROT_WRITE:数据可写;
- PROT_EXEC:数据可执行;
- PROT_NONE:数据不可访问;
- MAP_SHARED:该标志表示,调用进程对被映射内存区的数据所做的修改对于共享该内存区的所有进程都可见,而且确实改变其底层的支撑对象(一个文件对象或是一个共享内存区对象)。
- MAP_PRIVATE:调用进程对被映射内存区的数据所做的修改只对该进程可见,而不改变其底层支撑对象。
- MAP_FIXED:该标志表示准确的解释start参数,一般不建议使用该标志,对于可移植的代码,应该把start参数置为NULL,且不指定MAP_FIXED标志。
#include <sys/mman.h> int munmap(void *start, size_t len); //成功返回0,出错返回-1
#include <sys/mman.h> int msync(void *start, size_t len, int flags); //成功返回0,出错返回-1
- MS_ASYNC:异步写,一旦写操作由内核排入队列,就立刻返回;
- MS_SYNC:同步写,要等到写操作完成后才返回。
- MS_INVALIDATE:使该文件的其他内存映射的副本全部失效。
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> int main(){ int *memPtr; memPtr=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,0,0); if(memPtr==MAP_FAILED){ perror("mmap failed"); exit(-1); } *memPtr=0; if(fork()==0){ *memPtr=1; printf("child -- %d\n",*memPtr); exit(0); } sleep(1); printf("father -- %d\n",*memPtr); return 0; }
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #define PATH_NAME "/tmp/memmap1" int main(){ int fd; fd=open(PATH_NAME,O_RDWR|O_CREAT,0666); if(fd<0){ perror("open failed"); exit(fd); } if(ftruncate(fd,sizeof(int))<0){ perror("change file size failed"); close(fd); exit(-1); } int *memPtr; memPtr=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); close(fd); if(memPtr==MAP_FAILED){ perror("mmap failed"); exit(-1); } *memPtr=10; printf("write:%d\n",*memPtr); return 0; }
- 通过shm_open创建或打开一个POSIX共享内存对象;
- 然后调用mmap将它映射到当前进程的地址空间;
#include <sys/mman.h> int shm_open(const char *name, int oflag, mode_t mode); //成功返回非负的描述符,失败返回-1 int shm_unlink(const char *name); //成功返回0,失败返回-1
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #define PATH_NAME "/shm" int main(){ int fd; fd=shm_open(PATH_NAME,O_RDWR|O_CREAT,0666); if(fd<0){ perror("open failed"); exit(fd); } if(ftruncate(fd,sizeof(int))<0){ perror("change file size failed"); close(fd); exit(-1); } int *memPtr; memPtr=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); close(fd); if(memPtr==MAP_FAILED){ perror("mmap failed"); exit(-1); } *memPtr=10; printf("write:%d\n",*memPtr); return 0; }
读取
#include <unistd.h> #include <sys/types.h> #include <error.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #define PATH_NAME "/shm" int main(){ int fd; fd=shm_open(PATH_NAME,O_RDWR|O_CREAT,0666); if(fd<0){ perror("open failed"); exit(fd); } if(ftruncate(fd,sizeof(int))<0){ perror("change file size failed"); close(fd); exit(-1); } int *memPtr; memPtr=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); close(fd); if(memPtr==MAP_FAILED){ perror("mmap failed"); exit(-1); } printf("read:%d\n",*memPtr); shm_unlink(PATH_NAME); return 0; }