用到的函數: 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; }