一. 信號量
l信號量: 解決進程之間的同步與互斥的IPC機制
1 union semun { 2 int val; 3 struct semid_ds *buf; 4 unsigned short *array; 5 }; 6 7 // 將信號量sem_id設置爲init_value 8 int init_sem(int sem_id,int init_value) { 9 union semun sem_union; 10 sem_union.val=init_value; 11 if (semctl(sem_id,0,SETVAL,sem_union)==-1) { 12 perror("Sem init"); 13 exit(1); 14 } 15 return 0; 16 } 17 // 刪除sem_id信號量 18 int del_sem(int sem_id) { 19 union semun sem_union; 20 if (semctl(sem_id,0,IPC_RMID,sem_union)==-1) { 21 perror("Sem delete"); 22 exit(1); 23 } 24 return 0; 25 } 26 // 對sem_id執行p操作 27 int sem_p(int sem_id) { 28 struct sembuf sem_buf; 29 sem_buf.sem_num=0;//信號量編號 30 sem_buf.sem_op=-1;//P操作 31 sem_buf.sem_flg=SEM_UNDO;//系統退出前未釋放信號量,系統自動釋放 32 if (semop(sem_id,&sem_buf,1)==-1) { 33 perror("Sem P operation"); 34 exit(1); 35 } 36 return 0; 37 } 38 // 對sem_id執行V操作 39 int sem_v(int sem_id) { 40 struct sembuf sem_buf; 41 sem_buf.sem_num=0; 42 sem_buf.sem_op=1;//V操作 43 sem_buf.sem_flg=SEM_UNDO; 44 if (semop(sem_id,&sem_buf,1)==-1) { 45 perror("Sem V operation"); 46 exit(1); 47 } 48 return 0; 49 }
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/types.h> 5 #include <unistd.h> 6 #include <sys/sem.h> 7 #include <sys/ipc.h> 8 #include "sem_com.c" 9 10 #define DELAY_TIME 3 11 12 int main() { 13 pid_t pid; 14 // int sem_id; 15 // key_t sem_key; 16 17 // sem_key=ftok(".",'a'); 18 // 以0666且create mode創建一個信號量,返回給sem_id 19 // sem_id=semget(sem_key,1,0666|IPC_CREAT); 20 // 將sem_id設爲1 21 // init_sem(sem_id,1); 22 23 if ((pid=fork())<0) { 24 perror("Fork error!\n"); 25 exit(1); 26 } else if (pid==0) { 27 // sem_p(sem_id); // P操作 28 printf("Child running...\n"); 29 sleep(DELAY_TIME); 30 printf("Child %d,returned value:%d.\n",getpid(),pid); 31 // sem_v(sem_id); // V操作 32 exit(0); 33 } else { 34 // sem_p(sem_id); // P操作 35 printf("Parent running!\n"); 36 sleep(DELAY_TIME); 37 printf("Parent %d,returned value:%d.\n",getpid(),pid); 38 // sem_v(sem_id); // V操作 39 // waitpid(pid,0,0); 40 // del_sem(sem_id); 41 exit(0); 42 } 43 44 }
在以上程序註釋//未去掉時,即沒用信號量機制時,其結果爲:
顯然,此處存在競爭條件。
在以上程序註釋//去掉後,即使用信號量機制,其結果爲:
由於父子進程採用同一信號量且均執行各自PV操作,故必先等一個進程的V操作後,另一個進程才能工作。
二. 共享內存
eg. 下面這個例子完成:父進程從stdin讀取字符串並保存到共享內存中,子進程從共享內存中讀出數據並輸出到stdout
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/types.h> 5 #include <sys/ipc.h> 6 #include <sys/shm.h> 7 8 #define BUFFER_SIZE 2048 9 10 int main() { 11 pid_t pid; 12 int shmid; 13 char *shm_addr; 14 char flag[]="Parent"; 15 char buff[BUFFER_SIZE]; 16 // 創建當前進程的私有共享內存 17 if ((shmid=shmget(IPC_PRIVATE,BUFFER_SIZE,0666))<0) { 18 perror("shmget"); 19 exit(1); 20 } else 21 printf("Create shared memory: %d.\n",shmid); 22 23 // ipcs 命令往標準輸出寫入一些關於活動進程間通信設施的信息 24 // -m 表示共享內存 25 printf("Created shared memory status:\n"); 26 system("ipcs -m"); 27 28 if((pid=fork())<0) { 29 perror("fork"); 30 exit(1); 31 }else if (pid==0) { 32 // 自動分配共享內存映射地址,爲可讀可寫,映射地址返回給shm_addr 33 if ((shm_addr=shmat(shmid,0,0))==(void*)-1) { 34 perror("Child:shmat"); 35 exit(1); 36 }else 37 printf("Child: Attach shared-memory: %p.\n",shm_addr); 38 39 printf("Child Attach shared memory status:\n"); 40 system("ipcs -m"); 41 // 比較shm_addr,flag的長度爲strlen(flag)的字符 42 // 當其內容相同時,返回0 43 // 否則返回(str1[n]-str2[n]) 44 while (strncmp(shm_addr,flag,strlen(flag))) { 45 printf("Child: Waiting for data...\n"); 46 sleep(10); 47 } 48 49 strcpy(buff,shm_addr+strlen(flag)); 50 printf("Child: Shared-memory: %s\n",buff); 51 // 刪除子進程的共享內存映射地址 52 if (shmdt(shm_addr)<0) { 53 perror("Child:shmdt"); 54 exit(1); 55 }else 56 printf("Child: Deattach shared-memory.\n"); 57 58 printf("Child Deattach shared memory status:\n"); 59 system("ipcs -m"); 60 61 }else{ 62 sleep(1); 63 // 自動分配共享內存映射地址,爲可讀可寫,映射地址返回給shm_addr 64 if ((shm_addr=shmat(shmid,0,0))==(void*)-1) { 65 perror("Parent:shmat"); 66 exit(1); 67 }else 68 printf("Parent: Attach shared-memory: %p.\n",shm_addr); 69 70 printf("Parent Attach shared memory status:\n"); 71 system("ipcs -m"); 72 // shm_addr爲flag+stdin 73 sleep(1); 74 printf("\nInput string:\n"); 75 fgets(buff,BUFFER_SIZE-strlen(flag),stdin); 76 strncpy(shm_addr+strlen(flag),buff,strlen(buff)); 77 strncpy(shm_addr,flag,strlen(flag)); 78 // 刪除父進程的共享內存映射地址 79 if (shmdt(shm_addr)<0) { 80 perror("Parent:shmdt"); 81 exit(1); 82 }else 83 printf("Parent: Deattach shared-memory.\n"); 84 85 printf("Parent Deattach shared memory status:\n"); 86 system("ipcs -m"); 87 // 保證父進程在刪除共享內存前,子進程能讀到共享內存的內容 88 waitpid(pid,NULL,0); 89 // 刪除共享內存 90 if (shmctl(shmid,IPC_RMID,NULL)==-1) { 91 perror("shmct:IPC_RMID"); 92 exit(1); 93 }else 94 printf("Delete shared-memory.\n"); 95 96 printf("Child Delete shared memory status:\n"); 97 system("ipcs -m"); 98 99 printf("Finished!\n"); 100 } 101 102 exit(0); 103 }