Linux进程间通信——使用信号量
这篇文章将讲述别一种进程间通信的机制——信号量。注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物。有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号。下面就进入信号量的讲解。
1 int semget(key_t key, int num_sems, int sem_flags);
1 int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
sem_id是由semget返回的信号量标识符,sembuf结构的定义如下:
1 struct sembuf{ 2 short sem_num;//除非使用一组信号量,否则它为0 3 short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作, 4 //一个是+1,即V(发送信号)操作。 5 short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号, 6 //并在进程没有释放该信号量而终止时,操作系统释放信号量 7 };
1 int semctl(int sem_id, int sem_num, int command, ...);
如果有第四个参数,它通常是一个union semum结构,定义如下:
1 union semun{ 2 int val; 3 struct semid_ds *buf; 4 unsigned short *arry; 5 };
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <sys/sem.h> 9 10 union semun 11 { 12 int val; 13 struct semid_ds *buf; 14 unsigned short *arry; 15 }; 16 17 static int sem_id = 0; 18 19 static int set_semvalue(); 20 static void del_semvalue(); 21 static int semaphore_p(); 22 static int semaphore_v(); 23 24 int main(int argc, char *argv[]) 25 { 26 char message = ‘X‘; 27 int i = 0; 28 29 //创建信号量 30 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT); 31 32 if(argc > 1) 33 { 34 //程序第一次被调用,初始化信号量 35 if(!set_semvalue()) 36 { 37 fprintf(stderr, "Failed to initialize semaphore\n"); 38 exit(EXIT_FAILURE); 39 } 40 //设置要输出到屏幕中的信息,即其参数的第一个字符 41 message = argv[1][0]; 42 sleep(2); 43 } 44 for(i = 0; i < 10; ++i) 45 { 46 //进入临界区 47 if(!semaphore_p()) 48 exit(EXIT_FAILURE); 49 //向屏幕中输出数据 50 printf("%c", message); 51 //清理缓冲区,然后休眠随机时间 52 fflush(stdout); 53 sleep(rand() % 3); 54 //离开临界区前再一次向屏幕输出数据 55 printf("%c", message); 56 fflush(stdout); 57 //离开临界区,休眠随机时间后继续循环 58 if(!semaphore_v()) 59 exit(EXIT_FAILURE); 60 sleep(rand() % 2); 61 } 62 63 sleep(10); 64 printf("\n%d - finished\n", getpid()); 65 66 if(argc > 1) 67 { 68 //如果程序是第一次被调用,则在退出前删除信号量 69 sleep(3); 70 del_semvalue(); 71 } 72 exit(EXIT_SUCCESS); 73 } 74 75 static int set_semvalue() 76 { 77 //用于初始化信号量,在使用信号量前必须这样做 78 union semun sem_union; 79 80 sem_union.val = 1; 81 if(semctl(sem_id, 0, SETVAL, sem_union) == -1) 82 return 0; 83 return 1; 84 } 85 86 static void del_semvalue() 87 { 88 //删除信号量 89 union semun sem_union; 90 91 if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1) 92 fprintf(stderr, "Failed to delete semaphore\n"); 93 } 94 95 static int semaphore_p() 96 { 97 //对信号量做减1操作,即等待P(sv) 98 struct sembuf sem_b; 99 sem_b.sem_num = 0; 100 sem_b.sem_op = -1;//P() 101 sem_b.sem_flg = SEM_UNDO; 102 if(semop(sem_id, &sem_b, 1) == -1) 103 { 104 fprintf(stderr, "semaphore_p failed\n"); 105 return 0; 106 } 107 return 1; 108 } 109 110 static int semaphore_v() 111 { 112 //这是一个释放操作,它使信号量变为可用,即发送信号V(sv) 113 struct sembuf sem_b; 114 sem_b.sem_num = 0; 115 sem_b.sem_op = 1;//V() 116 sem_b.sem_flg = SEM_UNDO; 117 if(semop(sem_id, &sem_b, 1) == -1) 118 { 119 fprintf(stderr, "semaphore_v failed\n"); 120 return 0; 121 } 122 return 1; 123 }
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(int argc, char *argv[]) 5 { 6 char message = ‘X‘; 7 int i = 0; 8 if(argc > 1) 9 message = argv[1][0]; 10 for(i = 0; i < 10; ++i) 11 { 12 printf("%c", message); 13 fflush(stdout); 14 sleep(rand() % 3); 15 printf("%c", message); 16 fflush(stdout); 17 sleep(rand() % 2); 18 } 19 sleep(10); 20 printf("\n%d - finished\n", getpid()); 21 exit(EXIT_SUCCESS); 22 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。