转自:
http://shihaiyang.iteye.com/blog/492306
有关结构体
1.sem
- struct sem {
- short sempid; /* pid of last operation */
- ushort semval; /* current value */
- ushort semncnt; /* num procs awaiting increase in semval */
- ushort semzcnt; /* num procs awaiting semval = 0 */
- };
sem_pid 成员保存了最近一次操作信号量的进程的pid。
sem_semval 成员保存着信号量的计数值。
sem_semncnt 成员保存着等待使用资源的进程数目。
sem_semzcnt 成员保存等待资源完全空闲的的进程数目。
2.semun
semun联合体在senctl()函数中使用,提供 senctl()操作所需要的信息。
- union semun {
- int val; /* value for SETVAL */
- struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
- ushort *array; /* array for GETALL & SETALL */
- struct seminfo *__buf; /* buffer for IPC_INFO */
- void *__pad;
- };
3.sembuf
sembuf结构体被semop()函数用来定义对信号量对象的基本操作
- struct sembuf {
- unsigned short sem_num; /* semaphore index in array */
- short sem_op; /* semaphore operation */
- short sem_flg; /* operation flags */
- };
sem_num 成员为接受操作的信号量在信号量数组中的序号(数组下标)。
sem_op 成员定义了进行的操作(可以是正、负和零)。
sem_flg 是控制操作行为的标志。
4.semid_qs
和msgqid_ds类似,semid_qs结构被系统用来储存每个信号量对象的有关信息。
- struct semid_ds {
- struct ipc_perm sem_perm; /* permissions .. see ipc.h */
- __kernel_time_t sem_otime; /* last semop time */
- __kernel_time_t sem_ctime; /* last change time */
- struct sem *sem_base; /* ptr to first semaphore in array */
- struct sem_queue *sem_pending; /* pending operations to be processed */
- struct sem_queue **sem_pending_last; /* last pending operation */
- struct sem_undo *undo; /* undo requests on this array */
- unsigned short sem_nsems; /* no. of semaphores in array */
- };
其中,
sem_perm 成员保存了信号量对象的存取权限以及其他一些信息。
sem_otime 成员保存了最近一次semop()操作的时间。
sem_ctime 成员保存了信号量对象最近一次改动发生的时间。
sem_base 指针保存着信号量数组的起始地址。
sem_pending 指针保存着还没有进行的操作。
sem_pending_last 指针保存着最后一个还没有进行的操作。
sem_undo 成员保存了 undo请求的数目。
sem_nsems 成员保存了信号量数组的成员数目。
有关的函数
1.semget()
使用semget()函数来建立新的信号量对象或者获取已有对象的标识符。
系统调用: semget()
函数声明: int semget(key_t key,int nsems,int semflg);
返回值: semaphore set IPC identifier on success
- int open_semaphore_set(key_t keyval, int numsems)
- {
- int sid;
- if(!numsems) return(-1);
- if((sid=semget(keyval,numsems,IPC_CREAT|0660))==-1)
- {
- return(-1);
- }
- return(sid);
- }
2.semop()
使用这个函数来改变信号量对象中各个信号量的状态。
系统调用: semop()
函数声明: int semop(int semid, struct sembuf *sops, unsigned int nsops);
返回值: 0 on success (all operations performed)
第一个参数 semid是要操作的信号量对象的标识符。
第二个参数 sops是sembuf的数组,它定义了semop()函数所要进行的操作序列。
第三个参数 nsops保存着sops数组的长度,也即semop()函数将进行的操作个数。
3.semctl()
和消息队列的msgctl()函数类似,semctl()函数被用来直接对信号量对象进行控制
系统调用: semctl()
函数声明: int semctl(int semid, int semnum, int cmd, union semun arg);
返回值: positive integer on success
比较一下这两个函数的参数我们回发现一些细微的差别。首先,因为信号量对象事实上是多个信息量的集合而非单一的个体,所以在进行操作时,不仅需要指定对象的标识符,还需要用信号量在集合中的序号来指定具体的信号量个体。
两个函数都有cmd参数, 指定了函数进行的具体操作。 不过,和msgctl()函数相比, semctl()函数可以进行的操作要多得多:
IPC_STAT 取得信号量对象的 semid_ds 结构信息,并将其储存在 arg 参数中 buf 指针所指内存中返回。
IPC_SET 用 arg 参数中 buf 的数据来设定信号量对象的的 semid_ds 结构信息。和消息队列对象一样,能被这个函数设定的只有少数几个参数。
IPC_RMID 从内存中删除信号量对象。
GETALL 取得信号量对象中所有信号量的值,并储存在 arg 参数中的 array 数组中返回。
GETNCNT 返回正在等待使用某个信号量所控制的资源的进程数目。
GETPID 返回最近一个对某个信号量调用semop()函数的进程的 pid。
GETVAL 返回对象那某个信号量的数值。
GETZCNT 返回正在等待某个信号量所控制资源被全部使用的进程数目。
SETALL 用 arg 参数中 array数组的值来设定对象内各个信号量的值。
SETVAL 用 arg 参数中val成员的值来设定对象内某个信号量的值。
- int get_sem_val(int sid, int semnum)
- {
- return(semctl(sid,semnum,GETVAL,0));
- }
- void init_semaphore(int sid, int semnum, int initval)
- {
- union semun semopts;
- semopts.val=initval;
- semctl(sid, semnum, SETVAL, semopts);
- }
在消息队列和信号量对象中,都有 IPC_STAT 和 IPC_SET 的操作。但是由于传递参数的类型不同,造成了它们在使用上的差别。在 msgctl()函数中,IPC_STAT 操作只是简单的将内核内 msgqid_ds 结
构的地址赋予buf参数(是一个指针)。而在semctl()函数中, IPC_STAT操作是将 semid_ds 的内容拷贝到 arg 参数的 buf 成员指针所指的内存中。所以,下面的代码会产生错误,而 msgctl()函数的
类似代码却不会:
- void getmode(int sid)
- {
- int rc;
- union semun semopts;
- /*下面的语句会产生错误*/
- if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)
- {
- perror("semctl");
- }
- printf("Pemission Mode were %o\n", semopts.buf->sem_perm.mode);
- return;
- }
- void getmode(int sid)
- {
- int rc;
- union semun semopts;
- struct semid_ds mysemds;
- /*给buf指针准备一块内存*/
- semopts.buf=&mysemds;
- /*现在OK了*/
- if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)
- {
- perror("semctl");
- }
- printf("Pemission Mode were %o\n", semopts.buf->sem_perm.mode);
- return;
- }
实例:
- semtool.c
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define SEM_RESOURCE_MAX 1 /*Initial value of all semaphores*/
- void opensem(int *sid, key_t key);
- void createsem(int *sid, key_t key, int members);
- void locksem(int sid, int member);
- void unlocksem(int sid, int member);
- void removesem(int sid);
- unsigned short get_member_count(int sid);
- int getval(int sid, int member);
- void dispval(int sid,int member);
- void changemode(int sid, char *mode);
- void usage(void);
- int main(int argc, char *argv[])
- {
- key_t key;
- int semset_id;
- if(argc == 1) usage();
- /*Create unique key via call to ftok()*/
- key=ftok(".",'s');
- switch(tolower(argv[1][0]))
- {
- case 'c':
- if(argc!=3)usage();
- createsem(&semset_id, key, atoi(argv[2]));
- break;
- case 'l':
- if(argc!=3) usage();
- opensem(&semset_id, key);
- locksem(semset_id, atoi(argv[2]));
- break;
- case 'u':
- if(argc!=3) usage();
- opensem(&semset_id, key);
- unlocksem(semset_id, atoi(argv[2]));
- break;
- case 'd':
- opensem(&semset_id,key);
- removesem(semset_id);
- break;
- case 'm':
- opensem(&semset_id, key);
- changemode(semset_id, argv[2]);
- break;
- default:
- usage();
- }
- return(0);
- }
- void opensem(int *sid, key_t key)
- {
- /*Open the semaphore set ---do not creat!*/
- if((*sid=semget(key, 0 , 0666)==-1)
- {
- printf("Semaphore set does not exist!\n");
- exit(1);
- }
- }
- void createsem(int *sid, key_t key, int members)
- {
- int cntr;
- union semun semopts;
- if(members > SEMMSL){
- printf("Sorry,max number of semaphores in a set is %d\n",SEMMSL);
- exit(1);
- }
- printf("Attempting to create new semaphore set with %d members\n",members);
- if((*sid=semget(key, members, IPC_CREAT|IPC_EXCL|0666))==-1)
- {
- fprintf(stderr,"Semaphore set already exist!\n");
- exit(1);
- }
- semopts.val= SEM_RESOURCE_MAX;
- /*Initialize all members(could be done with SETALL)*/
- for(cntr=0;cntr<members;cntr++)
- {
- semctl(*sid, cntr, SETVAL, semopts);
- }
- }
- void locksem(int sid, int member)
- {
- struct sembuf sem_lock={0, -1, IPC_NOWAIT};
- if(member <0 ||member>(get_member_count(sid) -1))
- {
- fprintf(stderr,"semaphore member %d out of range\n", member);
- return;
- }
- /*Attempt to lock the semphore set*/
- if(!getval(sid, member))
- {
- fprintf(stderr,"Semaphore resources exhausted (no lock)\n")
- exit(1);
- }
- sem_lock.sem_num =member;
- if((semop(sid, &sem_lock, 1)==-1)
- {
- fprintf, "Lock faild\n");
- exit(1);
- }
- else
- printf("Semaphore resources decremented by one (locked)\n");
- dispval(sid ,member);
- }
- void unlocksem(int sid, int member)
- {
- struct sembuf sem_unlock={member, 1, IPC_NOWAIT};
- int semval;
- if(member<0 || member>(get_member_count(sid)-1))
- {
- fprintf(stderr,"Semaphore member %d out of range\n",member);
- return;
- }
- /*Is the semaphore set locked? */
- semval =getval(sid, member);
- if(semval==SEM_REOURSE_MAX){
- fprintf(stderr, "Semaphore not locked!\n");
- exit(1);
- }
- sem_unlock.sem_num = member;
- /*Attempt to lock the semaphore set*/
- if((semop(sid, &sem_unlock, 1))==-1)
- {
- fprintf(stderr, "Unlock failed\n");
- exit
- }
- else
- printf("Semaphore resources incremented by one(unlocked)\n");
- dispval(sid, member);
- }
- void removesem(int sid)
- {
- semctl(sid, 0, IPC_RMID,0);
- print("Semaphore removed\n");
- }
- unsigned short get_member_count(int sid)
- {
- union semum semopts;
- struct semid_ds mysemds;
- semopts.buf= &mysemds;
- /*Return number of member in the semaphore set*/
- int rc;
- if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)
- {
- perror("semctl");
- return(-1)
- }
- return(semopts.buf->sem_nsems);
- }
- int getval(int sid, int member)
- {
- int semval;
- semval= semctl(sid, member,GETVAL, 0)
- reval semval;
- }
- void changemode(int sid, char *mode)
- {
- int rc;
- union semun semopts;
- struct semid_ds mysemds;
- /*Get current values for internal data structure */
- semopts.buf=&mysemds;
- rc = semctl(sid, 0, IPC_STAT, semopts);
- if(rc ==-1)
- {
- perror("semctl");
- exit(1);
- }
- printf("Old permission were %o\n", semopts.buf->perm.mode);
- /* Change the permission on the semaphore */
- sscanf(mode,"%ho",&semopts.buf->sem_perm.mode);
- /*Update the internal data structure */
- semctl(sid,0, IPC_SET, semopts);
- printf("Updated......\n");
- }
- void dispval(int sid, int member)
- {
- int semval;
- semval= semctl(sid, member, GETVAL,0);
- printf("semval for member %d is %d\n", member ,semval);
- }
- void usage(void)
- {
- fprintf(stderr, "semtool -Autility for thinking with semaphores\n");
- fprintf(stderr, "\nUSAGE: semtool (c)reate <semcount>\n");
- fprintf(stderr, " (l)ock <sem #>\n");
- fprintf(stderr, " (u)nlock <sem #>\n");
- fprintf(stderr, " (d)elete\n");
- fprintf(stderr, " (m)ode <mode>\n");
- exit(1);
- }