有关结构体
1.sem
- struct sem {
- short sempid;
- ushort semval;
- ushort semncnt;
- ushort semzcnt;
- };
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;
- struct semid_ds *buf;
- ushort *array;
- struct seminfo *__buf;
- void *__pad;
- };
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;
- short sem_op;
- short sem_flg;
- };
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;
- __kernel_time_t sem_otime;
- __kernel_time_t sem_ctime;
- struct sem *sem_base;
- struct sem_queue *sem_pending;
- struct sem_queue **sem_pending_last;
- struct sem_undo *undo;
- unsigned short sem_nsems;
- };
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);
- }
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);
}
函数的第二个参数 nsems 是信号量对象所特有的,它指定了新生成的信号量对象中信号量的数目,也就是信号量数组成员的个数。
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));
- }
int get_sem_val(int sid, int semnum)
{
return(semctl(sid,semnum,GETVAL,0));
}
上面的代码返回信号量对象中某个信号量的值。注意这里 semctl()函数的最后一个参数取的是零,这是因为执行 GETVAL 命令时这个参数被自动忽略了。
- void init_semaphore(int sid, int semnum, int initval)
- {
- union semun semopts;
- semopts.val=initval;
- semctl(sid, semnum, SETVAL, semopts);
-
- }
void init_semaphore(int sid, int semnum, int initval)
{
union semun semopts;
semopts.val=initval;
semctl(sid, semnum, SETVAL, semopts);
}
上面的代码用 initval参数来设定信号量对象中某个信号量的值。
在消息队列和信号量对象中,都有 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;
/*下面的语句会产生错误*/
if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)
{
perror("semctl");
}
printf("Pemission Mode were %o/n", semopts.buf->sem_perm.mode);
return;
}
为什么呢?因为实现没有给 buf 指针分配内存,其指向是不确定的。这种“不定向”的指针是 C 程序中最危险的陷阱之一。改正这个错误,只需要提前给 buf 指针准备一块内存。下面是修改过的代码:
- void getmode(int sid)
- {
- int rc;
- union semun semopts;
- struct semid_ds mysemds;
-
- semopts.buf=&mysemds;
-
-
- 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
- #include
- #include
- #include
- #include
- #include
-
- #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();
-
-
- 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)
- {
-
- 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;
-
- for(cntr=0;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;
-
-
- }
-
-
- 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;
-
- }
-
-
-
- semval =getval(sid, member);
- if(semval==SEM_REOURSE_MAX){
-
- fprintf(stderr, "Semaphore not locked!/n");
- exit(1);
-
- }
-
- sem_unlock.sem_num = member;
-
-
- 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;
-
- 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;
-
-
-
- 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);
-
-
- sscanf(mode,"%ho",&semopts.buf->sem_perm.mode);
-
-
- 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 /n");
- fprintf(stderr, " (l)ock /n");
- fprintf(stderr, " (u)nlock /n");
- fprintf(stderr, " (d)elete/n");
- fprintf(stderr, " (m)ode /n");
- exit(1);
-
- }