Linux信号量PV操作

Linux信号量PV操作
semop操作中:sembuf结构的sem_flg成员可以为0、IPC_NOWAIT、SEM_UNDO 。为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的

 semop操作中:sembuf结构的sem_flg成员可以为0、IPC_NOWAIT、SEM_UNDO 。为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量。除非你对信号量的行为有特殊的要求,否则应该养成设置sem_flg为SEM_UNDO的好习惯。 
 1: //假设两个进程(父子进程)对一个文件进行写操作,但是这个文件同一时间只能有一个进程进行写操作。
 2: //利用信号量实现pv操作
 3: #include <stdio.h>
 4: #include <stdlib.h>
 5: #include <sys/ipc.h>
 6: #include <sys/sem.h>
 7: #include <sys/types.h>
 8: #include <fcntl.h>
 9: struct sembuf sops;
 10: static int sid;
 11: //创建一个新的信号量集
 12: int createSemset(void)
 13: {
 14: char* pathname="semset";
 15: if( access(pathname, F_OK)!=0 )
 16: {
 17: int fd=open(pathname, O_RDWR | O_CREAT, 0666);    
 18: if( fd<0 )
 19: {
 20: perror("open");
 21: return -1;
 22: }
 23: }
 24: key_t key=ftok(pathname, 'a');
 25: if( -1==key )
 26: {
 27: perror("ftok");
 28: return -1;
 29: }
 30: return semget(key, 1, IPC_CREAT | 0666) ;
 31: }
 32:  
 33: //P操作
 34: int P(void)
 35: {
 36: sops.sem_num=0;
 37: sops.sem_op=-1;
 38: sops.sem_flg=0;
 39: return semop(sid, &sops, 1);
 40: }
 41: //V操作
 42: int V(void)
 43: {
 44: sops.sem_num=0;
 45: sops.sem_op=1;
 46: sops.sem_flg=0;
 47: return semop(sid, &sops, 1);
 48: }
 49: int main(int argc, char *argv[])
 50: {
 51: sid=createSemset();
 52: if( -1==sid )
 53: {
 54: perror("createSemset");
 55: exit(1);
 56: }
 57:  
 58: if( -1==semctl(sid, 0, SETVAL, 1) )
 59: {
 60: perror("SETVAL");
 61: exit(1);
 62: }
 63: pid_t pid=fork();
 64: if( pid<0 )
 65: {
 66: perror("fork");
 67: exit(1);
 68: }
 69: else if( 0==pid )
 70: {
 71: while(1)
 72: {
 73: if( -1==P() )
 74: {
 75: printf("P操作失败! ");    
 76: exit(1);
 77: }
 78: printf("子进程正在对文件进行写操作! ");
 79: sleep(1);    
 80: printf("子进程写操作完毕,释放资源! ");
 81: if( -1==V() )
 82: {
 83: printf("V操作失败!");
 84: exit(1);
 85: }
 86: }
 87: }
 88: else
 89: {
 90: while(1)
 91: {
 92: if( -1==P() )
 93: {
 94: printf("P操作失败! ");    
 95: exit(1);
 96: }
 97: printf("父进程进程正在对文件进行写操作! ");    
 98: sleep(1);
 99: printf("父进程写操作完毕,释放资源! ");
 100: if( -1==V() )
 101: {
 102: printf("V操作失败!");
 103: exit(1);
 104: } ......
 1: void P(int semid)
 2: {
 3:     struct sembuf sem_p;
 4:     sem_p.sem_num = 0;
 5:     sem_p.sem_op = -1;
 6:     sem_p.sem_flg = SEM_UNDO;
 7:     if (semop(semid, &sem_p, 1) == -1) {
 8:         perror("p op failed ");
 9:         exit(1);
 10:     }
 11: }
 12:  
 13: void V(int semid)
 14: {
 15:     struct sembuf sem_p;
 16:     sem_p.sem_num = 0;
 17:     sem_p.sem_op = 1;
 18:     sem_p.sem_flg = SEM_UNDO;
 19:     if (semop(semid, &sem_p, 1) == -1) {
 20:         perror("v op failed ");
 21:         exit(1);
 22:     }
 23: }

PV原语通过操作信号量来处理进程间的同步与互斥的问题。其核心就是一段不可分割不可中断的程序。

信号量的概念1965年由著名的荷兰计算机科学家Dijkstra提出,其基本思路是用一种新的变量类型(semaphore)来记录当前可用资源的数量。有两种实现方式:1)semaphore的取值必须大于或等于0。0表示当前已没有空闲资源,而正数表示当前空闲资源的数量;2) semaphore的取值可正可负,负数的绝对值表示正在等待进入临界区的进程个数。

信号量是由操作系统来维护的,用户进程只能通过初始化和两个标准原语(P、V原语)来访问。初始化可指定一个非负整数,即空闲资源总数。

P原语:P是荷兰语Proberen(测试)的首字母。为阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;

V原语:V是荷兰语Verhogen(增加)的首字母。为唤醒原语,负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。

具体PV原语对信号量的操作可以分为三种情况:

1)把信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。

实现过程:

P(mutex); // mutex的初始值为1 访问该共享数据;

V(mutex);

非临界区

2)把信号量视为是某种类型的共享资源的剩余个数,实现对一类共享资源的访问。

实现过程:

P(resource); // resource的初始值为该资源的个数N 使用该资源;

V(resource); 非临界区

3)把信号量作为进程间的同步工具

实现过程:

临界区C1;

P(S);

V(S);

临界区C2;

你可能感兴趣的:(linux,职场,pv,信号量,休闲)