用到的函数: Liunux – ftok函数
- 部分内核的宏:
#ifndef _ASM_GENERIC_ERRNO_BASE_H #define _ASM_GENERIC_ERRNO_BASE_H #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* I/O error */ #define ENXIO 6 /* No such device or address */ #define E2BIG 7 /* Argument list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ #define ECHILD 10 /* No child processes */ #define EAGAIN 11 /* Try again */ #define ENOMEM 12 /* Out of memory */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ #define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device or resource busy */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Cross-device link */ #define ENODEV 19 /* No such device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* File table overflow */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Not a typewriter */ #define ETXTBSY 26 /* Text file busy */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Illegal seek */ #define EROFS 30 /* Read-only file system */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ #define EDOM 33 /* Math argument out of domain of func */ #define ERANGE 34 /* Math result not representable */ #endif
- 非同步机制
shm_write.c
shm_read.c#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <errno.h> #include <asm-generic/errno-base.h> #include <unistd.h> #include <strings.h> #include <string.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) struct use_buf { int flag; /*由于这里没有使用信号量实现互斥操作,所以使用一个标志(1:表示可读,0:表示可写)来互斥操作同一块内存区*/ char buf[100]; // 数据 }; int main(void){ int shmid; key_t ret_fk; struct use_buf *shm_buf=NULL; if((ret_fk=ftok("/", 'a'))==-1){ handle_error("ftok"); } /*判断键值对应的共享内存是否存在,不存在创建共享内存*/ if((shmid=shmget(ret_fk, sizeof(struct use_buf), IPC_CREAT|IPC_EXCL|0600))==-1){ if(EEXIST==errno){ /*如果键值对应的共享内存已存在*/ shmid=shmget(ret_fk, sizeof(struct use_buf), 0); /*获取共享内存标识*/ printf("键值(%#x)对应的共享内存(%d)已存在\n",ret_fk,shmid); } else handle_error("shmget"); }else fprintf(stdout, "键值(%#x)创建共享内存成功,共享内存编号为%d\n",ret_fk,shmid); if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){ shmctl(shmid, IPC_RMID, NULL); handle_error("shmat"); /*共享内存映射,系统自动分配地址、共享内存可读写*/ } shm_buf->flag = 0; /*初始化标志*/ while(1){ if(1==shm_buf->flag){ /*数据未读走*/ // printf("Waiting...\n"); // sleep(1); }else{ bzero(shm_buf->buf, sizeof(shm_buf->buf)); printf("请输入数据:"); fgets(shm_buf->buf,sizeof(shm_buf->buf)-1,stdin); shm_buf->flag=1; /*数据写入完成,标志变成可读*/ if(!strncasecmp(shm_buf->buf, "quit", strlen("quit"))) break; } } if(-1==shmdt((struct use_buf *)shm_buf)){ handle_error("shndt"); /*解除当前进程与共享内存的映射*/ } if(-1==shmctl(shmid, IPC_RMID, NULL)){ handle_error("shnctl"); /*删除共享内存*/ } return 0; }
缺点: 由于没有采用同步机制,shm_read进程一直在循环,这种方式会将cpu资源耗完#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <errno.h> #include <asm-generic/errno-base.h> #include <unistd.h> #include <strings.h> #include <string.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) struct use_buf { int flag; //由于这里没有使用同步机制,使用一个标志,1:表示可读,0:表示可写*/ char buf[100]; // 数据 }; int main(void){ int shmid; key_t ret_fk; struct use_buf *shm_buf=NULL; if((ret_fk=ftok("/", 'a'))==-1){ handle_error("ftok"); } /*判断键值对应的共享内存是否存在,不存在创建共享内存*/ if((shmid=shmget(ret_fk, sizeof(struct use_buf), IPC_CREAT|IPC_EXCL|0600))==-1){ if(EEXIST==errno){ /*如果键值对应的共享内存已存在*/ shmid=shmget(ret_fk, sizeof(struct use_buf), 0); /*获取共享内存标识*/ printf("键值(%#x)对应的共享内存(%d)已存在\n",ret_fk,shmid); } else handle_error("shmget"); }else fprintf(stdout, "键值(%#x)创建共享内存成功,共享内存编号为%d\n",ret_fk,shmid); if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){ handle_error("shmat"); /*共享内存映射,系统自动分配地址、共享内存可读写*/ } while(1){ if(0==shm_buf->flag){ /*未写数据*/ // printf("Waiting...\n"); // sleep(1); }else{ printf("读出数据:"); fputs(shm_buf->buf,stdout); shm_buf->flag=0; /*数据写出完成,标志变成可写*/ if(!strncasecmp(shm_buf->buf, "quit", strlen("quit"))) break; } } if(-1==shmdt((struct use_buf *)shm_buf)){ handle_error("shndt"); /*解除当前进程与共享内存的映射*/ } return 0; }
- 同步机制
shm_write.c
shm_read.c#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <errno.h> #include <asm-generic/errno-base.h> #include <unistd.h> #include <strings.h> #include <string.h> #include "sem.h" #include <signal.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) struct use_buf { int flag; //不使用该标志,使用信号量互斥操作 char buf[100]; // 数据 }; int shmid; int semid; struct use_buf *shm_buf=NULL; void user_quit_handle(int signo){ if(SIGINT==signo){ system("killall INT shm_read"); /*关闭共享内存读进程*/ if(-1==shmdt((struct use_buf *)shm_buf)){ handle_error("shndt"); /*解除当前进程与共享内存的映射*/ } if(-1==shmctl(shmid, IPC_RMID, NULL)){ handle_error("shnctl"); /*删除共享内存*/ } if(-1==del_sem(semid)){ handle_error("del_sem"); /*删除信号量集*/ } exit(EXIT_SUCCESS); } } int main(void){ char tmp_buf[100]; /*判断键值对应的共享内存是否存在,不存在创建共享内存,存在返回共享内存标识符*/ if((shmid=shmget(ftok("/", 'a'), sizeof(struct use_buf), IPC_CREAT|0600))==-1){ handle_error("shmget"); } /*判断键值对应的信号量是否存在,不存在创建信号量,存在返回信号量标识符*/ if((semid=get_sem(ftok("/", 1), 2))== -1){ /*创建信号量集(两个信号量)对共享内存进行互斥同步操作*/ exit(EXIT_FAILURE); } if(-1==set_sem_val(semid, 0, 1)){//初始化为共享内存起始状态可写 exit(EXIT_FAILURE); } if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){ handle_error("shmat"); /*共享内存映射,系统自动分配地址、共享内存可读写*/ } if(SIG_ERR==signal(SIGINT, user_quit_handle)){ /*注册SIGINT信号处理函数*/ handle_error("signal"); } bzero(shm_buf->buf, sizeof(shm_buf->buf)); /*清空共享内存buf部分*/ while(1){ printf("请输入数据:"); bzero(tmp_buf, sizeof(tmp_buf)); if(NULL==fgets(tmp_buf,sizeof(tmp_buf)-1,stdin)){ perror("fgets"); } sem_P(semid, 0); /*写P操作*/ strncpy(shm_buf->buf, tmp_buf, strlen(tmp_buf)); if(!strncasecmp(tmp_buf, "quit", strlen("quit"))){ sem_V(semid, 1); /*读V操作*/ break; } sem_V(semid, 1); /*读V操作*/ } if(-1==shmdt((struct use_buf *)shm_buf)){ handle_error("shndt"); /*解除当前进程与共享内存的映射*/ } if(-1==shmctl(shmid, IPC_RMID, NULL)){ handle_error("shnctl"); /*删除共享内存*/ } if(-1==del_sem(semid)){ handle_error("del_sem"); /*删除信号量集*/ } return 0; }
优点: 采用同步机制,shm_write进程写后shm_read进程才读,cpu消耗接近零。#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <errno.h> #include <asm-generic/errno-base.h> #include <unistd.h> #include <strings.h> #include <string.h> #include "sem.h" #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) struct use_buf { int flag; //不使用该标志,使用信号量互斥操作 char buf[100]; // 数据 }; int main(void){ int shmid; int semid; struct use_buf *shm_buf=NULL; /*判断键值对应的共享内存是否存在,不存在创建共享内存,存在返回共享内存标识符*/ if((shmid=shmget(ftok("/", 'a'), sizeof(struct use_buf), IPC_CREAT|0600))==-1){ handle_error("shmget"); } /*判断键值对应的信号量是否存在,不存在创建信号量,存在返回信号量标识符*/ if((semid=get_sem(ftok("/", 1), 2))== -1){ /*创建信号量集(两个信号量)对共享内存进行互斥同步操作*/ exit(EXIT_FAILURE); } if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){ handle_error("shmat"); /*共享内存映射,系统自动分配地址、共享内存可读写*/ } while(1){ sem_P(semid, 1); /*读P操作*/ printf("读出数据:%s",shm_buf->buf); bzero(shm_buf->buf, sizeof(shm_buf->buf)); /*读出数据后清空共享内存buf部分*/ if(!strncasecmp(shm_buf->buf, "quit", strlen("quit"))){ sem_V(semid, 0); /*写V操作*/ break; } bzero(shm_buf->buf, sizeof(shm_buf->buf)); sem_V(semid, 0); /*写V操作*/ } if(-1==shmdt((struct use_buf *)shm_buf)){ handle_error("shndt"); /*解除当前进程与共享内存的映射*/ } return 0; }