zoukankan      html  css  js  c++  java
  • Linux IPC System V 信号量

    模型

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    ftok()              //获取key					
    semget()            //创建/获取信号量集		
    semctl()            //初始化信号量集			
    semop()             //操作信号量集			
    semctl()            //删除信号量集			
    

    ftok()

    //获取key值, key值是System V IPC的标识符,成功返回key,失败返回-1设errno
    //同pathname+同 proj_id==>同key_t;
    key_t ftok(const char *pathname, int proj_id);
    

    pathname :文件名
    proj_id: 1~255的一个数,表示project_id

    key_t key=ftok(".",100);	//“.”就是一个存在且可访问的路径, 100是假设的proj_id
    	if(-1==key)
    		perror("ftok"),exit(-1);
    

    semget():

    //创建/获取一个信号量集,成功返回semid,失败返回-1
    int semget(key_t key, int nsems, int semflg);
    

    nsems: 信号量集的大小/信号量的个数,0表示获取已经存在的信号量集
    semflg

    • IPC_CREAT :若不存在则创建, 需要在msgflg中"|权限信息"; 若存在则打开
    • IPC_EXCL :若存在则创建失败
    • 0 :获取已经存在的信号量集
    //create sem
    semid=semget(key,1,IPC_CREAT|IPC_EXCL|0664);
    if(-1==semid)
    	perror("semid"),exit(-1);
    

    semctl()

    //主要用于对指定的信号量集/信号量执行指定的操作,成功返回0,失败返回-1设errno
    int semctl(int semid, int semnum, int cmd, ...);
    

    semid: 信号量集的编号(哪个信号量集)
    semnum: 信号量集的下标(这个信号量集里的哪个信号量)
    cmd:具体的操作命令

    • IPC_STAT 将内核中与semid相关的信息拷贝到arg.buf指向的结构体中
    • IPC_SET将buf指向的semid_ds结构体的部分内容写入到内核中的相关数据结构中,同时更新sem_ctime成员
    • IPC_RMID 立即销毁指定的信号量集,调用的进程的的effective UID必须和信号量集的创建者或所有者相匹配,或者这个进程有足够的特权级别,此时第四个参数会被忽略
    • IPC_INFO(Linux-specific)返回系统对信号量集的限制到__buf指向的结构体seminfo中
    //_GNU_SOURCE
    struct  seminfo {
    	int 	semmap;  	/* Number of entries in semaphore map; unused within kernel */
    	int 	semmni;  	/* Maximum number of semaphore sets */
    	int 	semmns; 	/* Maximum number of semaphores in all semaphore sets */
    	int 	semmnu;  	/* System-wide maximum number of undo structures; unused within kernel */
    	int 	semmsl;  	/* Maximum number of semaphores in a set */
       	int 	semopm;  	/* Maximum number of operations for  semop(2) */
    	int 	semume;  	/* Maximum number of undo entries per process; unused within kernel */
     	int 	semusz;  	/* Size of struct sem_undo */
            int 	semvmx;  	/* Maximum semaphore value */
    	int 	semaem;  	/* Max. value that can be recorded for semaphore adjustment (SEM_UNDO) */
    };
    
    //semmsl, semmns, semopm, semmni可以通过/proc/sys/kernel/sem来设置
    
    • SEM_INFO (Linux-specific)返回和IPC_INFO一样的信息,除了以下方面:semusz成员返回当前系统中存在的信号量集的数目,semaem返回系统中所有信号量集中的信号量总数
    • SEM_STAT(Linux-specific)返回semid_ds结构,类似与IPC_STAT
    • GETALL 返回所有信号量的semval到arg.array中,忽略semnum
    • GETNCNT 返回信号量集第semnum个信号量的semcnt值
    • GETPID 返回信号量集第semnum个信号量的sempid值
    • GETVAL 返回信号量集第semnum个信号量的semval值
    • GETZCNT 返回信号量集第semnum个信号量的semzcnt值
    • SETALL 使用arg.array设置信号量集里的所有的信号量的semval值,同时更新信号量集的semid_ds结构体的sem_ctime成员的值
    • SETVAL返回信号量集第semnum个信号量的semval的值到arg.val中,同时更新信号量集的semid_ds结构体的sem_ctime成员的值

    the fourth argument:

    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) */
    };
    
    //<sys/sem.h>
    struct semid_ds {
    	struct ipc_perm	sem_perm;  	/* Ownership and permissions */
    	time_t 			sem_otime; 	/* Last semop time */
        time_t 			sem_ctime;	/* Last change time */
        unsigned short	sem_nsems; 	/* No. of semaphores in set */
    };
    
    //<sys/ipc.h>
    struct ipc_perm {
    	key_t  			__key; 	/* Key supplied to semget(2) */
    	uid_t   		uid;   	/* Effective UID of owner */
    	gid_t  		 	gid;   	/* Effective GID of owner */
    	uid_t   		cuid;  	/* Effective UID of creator */
    	gid_t			cgid;  	/* Effective GID of creator */
     	unsigned short 	mode;  	/* Permissions */
       	unsigned short 	__seq; 	/* Sequence number */
    };
    
    int res=semctl(semid,0,SETVAL,5);
    if(-1==res)
    	perror("semctl"),exit(-1);
    int res=semctl(semid,0,IPC_RMID);
    if(-1==res)
    	perror("semctl"),exit(-1);
    

    semop():

    //操作指定的信号量集,成功返回0,失败返回-1设errno
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    

    semid:信号集的ID(returned by semget())
    sops:结构体指针, 既可以指向结构体变量, 也可以指向结构体数组信号量集本质上是若干个信号量的集合, 可以实现对信号量的批处理

    struct sembuf{
    	unsigned short 	sem_num;	//信号量集的下标
    	short          	sem_op; 	//正数表示增加, 0表示不变, 负数表示减小
    	short          	sem_flg;	//操作标志,默认给0
    }
    

    nsops:结构体指针指向的元素个数, 也就是数组的大小

    例子

    Sys V IPC sem
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/sem.h>
    #include<signal.h>
    #include<stdio.h>
    #include<stdlib.h>
    int main(){
    	//get key
    	key_t key=ftok(".",200);
    	if(-1==key)
    		perror("ftok"),exit(-1);
    	printf("key=%d
    ",key);
    	//create sem
    	int semid=semget(key,0,0);
    	if(-1==semid)
    		perror("semget"),exit(-1);
    	printf("semid=%d
    ",semid);
    	//creat 10 children to take the shared resource
    	int i=0;
    	for(i=0;i<10;i++){		//创建10个进程, 当然,需要只给parent或child单独fork(), 否则就是2^10个进程
    		pid_t pid=fork();
    		if(-1==pid)
    			perror("fork"),exit(-1);
    		if(0==pid){
    
    			struct sembuf buf;		//准备占用资源, sem_op-1
    			buf.sem_num=0;		//信号量集下标
    			buf.sem_op=-1;		//信号量-1
    			buf.sem_flg=0;		//操作标志
    			int res=semop(semid,&buf,1/*结构体变量的个数*/);
    			if(-1==res)
    				perror("semop"),exit(-1);
    
    			sleep(20);			//模拟正在占用共享资源
    
    			buf.sem_op=1;		//占用完了, sem_op+1
    			res=semop(semid,&buf,1);
    			if(-1==res)
    				perror("semop"),exit(-1);
    
    			exit(0);				//终止子进程, 自然也就跳出了循环,防止再fork()
    		//	break;
    		}
    	}	
    	return 0;
    }
    //出现抢占的效果, 还没有全部释放完毕的时候就有进程抢到了已经释放的进程
    
  • 相关阅读:
    适用于实数范围的中缀表达式的 +
    Django官方文档学习2——数据库及模板
    github命令
    千行代码入门Python
    Notepad++配置Python运行环境
    Python常用网页字符串处理技巧
    requests设置headers,proxies,cookies
    Django官方文档学习1——第一个helloworld页面
    笔记本键盘上没有break键的解决方案
    Python beautifulsoup模块
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/5936135.html
Copyright © 2011-2022 走看看