寒假学习 第25天 (linux 高级编程) 笔记总结
一、信号量(进程同步)
模型
(1)创建或者得到信号量 semget
int semget(key_t key,
int nsems, //信号量数组的个数
int semflg); ////信号量的创建标记 创建:IPC_CREAT IPC_EXCL(防止重复创建),打开:就是0
(2)初始化信号量中指定下标的值 semctl
int semctl(int semid,
int semnum,
int cmd,//操作 SETVAL IPC_RMID 如果是IPC_RMID则semnu跟 ... 都无意义
...);
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};(3)根据信号量阻塞或者解除阻塞 semop
int semop(int semid, //共享信号量的ID
struct sembuf *sops, //描述对信号量的操作,操作可以是数组
unsigned nsops); //第二个参数的个数(操作个数) (如果是两个操作,两个操作都会执行)
struct sembuf成员:
unsigned short sem_num; //下标
short sem_op; //负数 够减函数返回不阻塞,不够减阻塞 / 正数 / 0 判定信号量是否 > 0 ,>0则阻塞直到信号量为0
short sem_flg; //建议为0控制坚持到搭配方式:
+(解除阻塞) -(阻塞)
0(阻塞) -(解除阻塞)
(4)删除信号量 semctl
semctl(semid,0,IPC_RMID);
例子1:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> int main(int argc, const char *argv[]) { key_t key; int semid; key=ftok(".",22); if(key==-1) printf("ftok error:%m\n"),exit(-1); semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666); //创建信号量 if(semid==-1) printf("semget error:%m\n") ,exit(-1); return 0; }
这样ipcs -s就会看到新增加的信号量
例子2:(用上面程序创建的信号量)
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ }; int main(int argc, const char *argv[]) { key_t key; int semid; key=ftok(".",22); if(key==-1) printf("ftok error:%m\n"),exit(-1); //semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666); //if(semid==-1) printf("semget error:%m\n") ,exit(-1); semid=semget(key,1,0); //得到信号量 if(semid==-1) printf("semget error:%m\n") ,exit(-1); printf("semid:%d\n",semid); union semun v; v.val=2; //初始值为2 int r; r=semctl(semid,0,SETVAL,v); //设置信号量的值 if(r==-1) printf("semctl error:%m\n"),exit(-1); //对信号量进行阻塞操作 struct sembuf op[2]; // 定义操作,这里定义了两个操作 op[0].sem_num=0; //信号量的下标 op[0].sem_op=-1; //信号量的操作单位与类型 -就是阻塞(不够减就等待) op[0].sem_flg=0; //操作标记 IPC_NOWAIT不管够不够减都要返回,够减就是正常方式返回,不够减异常方式返回 SEM_UNDO当程序异常退出,系统自动把操作恢复到原始值,用来解除死锁。一般这两个都用不到 while(1) { r=semop(semid,op,1); //val为2 执行2次就会阻塞 printf("解除阻塞\n"); } return 0; }
输出两次“解除阻塞” 后阻塞
运行下面的程序 又可以开始输出"解除阻塞"
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ }; int main(int argc, const char *argv[]) { key_t key; int semid; key=ftok(".",22); if(key==-1) printf("ftok error:%m\n"),exit(-1); //semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666); //if(semid==-1) printf("semget error:%m\n") ,exit(-1); semid=semget(key,1,0); //得到信号量 if(semid==-1) printf("semget error:%m\n") ,exit(-1); printf("semid:%d\n",semid); int r; //对信号量进行阻塞操作 struct sembuf op[2]; // 定义操作,这里定义了两个操作 op[0].sem_num=0; //信号量的下标 op[0].sem_op=+1; //信号量的操作单位与类型 -就是阻塞(不够减就等待) op[0].sem_flg=0; //操作标记 IPC_NOWAIT不管够不够减都要返回,够减就是正常方式返回,不够减异常方式返回 SEM_UNDO当程序异常退出,系统自动把操作恢复到原始值,用来解除死锁。一般这两个都用不到 while(1) { r=semop(semid,op,1); //val为2 执行2次就会阻塞 sleep(1); } return 0; }
@1: 牛逼