#include <linux/sem.h> #include <stdio.h> #include <errno.h> #define SEM_PATH "/unix/my_sem" #define max_tries 3 int semid; main() { int flag1,flag2,key,i,init_ok,tmperrno; struct semid_ds sem_info; struct seminfo sem_info2; union semun arg; //union semun: 请参考附录2 struct sembuf askfor_res, free_res; flag1=IPC_CREAT|IPC_EXCL|00666; flag2=IPC_CREAT|00666; key=ftok(SEM_PATH,'a'); //error handling for ftok here; init_ok=0; semid=semget(key,1,flag1);//create a semaphore set that only includes one semphore. if(semid<0) { tmperrno=errno; perror("semget"); if(tmperrno==EEXIST) //errno is undefined after a successful library call( including perror call) so it is saved //in tmperrno. { semid=semget(key,1,flag2); //flag2 只包含了IPC_CREAT标志, 参数nsems(这里为1)必须与原来的信号灯数目一致 arg.buf=&sem_info; for(i=0; i<max_tries; i++) { if(semctl(semid, 0, IPC_STAT, arg)==-1) { perror("semctl error"); i=max_tries;} else { if(arg.buf->sem_otime!=0){ i=max_tries; init_ok=1;} else sleep(1); } } if(!init_ok) // do some initializing, here we assume that the first process that creates the sem will // finish initialize the sem and run semop in max_tries*1 seconds. else it will not run // semop any more. { arg.val=1; if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error"); } } else {perror("semget error, process exit"); exit(); } } else //semid>=0; do some initializing { arg.val=1; if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error"); } //get some information about the semaphore and the limit of semaphore in redhat8.0 arg.buf=&sem_info; if(semctl(semid, 0, IPC_STAT, arg)==-1) perror("semctl IPC STAT"); printf("owner's uid is %d/n", arg.buf->sem_perm.uid); printf("owner's gid is %d/n", arg.buf->sem_perm.gid); printf("creater's uid is %d/n", arg.buf->sem_perm.cuid); printf("creater's gid is %d/n", arg.buf->sem_perm.cgid); arg.__buf=&sem_info2; if(semctl(semid,0,IPC_INFO,arg)==-1) perror("semctl IPC_INFO"); printf("the number of entries in semaphore map is %d /n", arg.__buf->semmap); printf("max number of semaphore identifiers is %d /n", arg.__buf->semmni); printf("mas number of semaphores in system is %d /n", arg.__buf->semmns); printf("the number of undo structures system wide is %d /n", arg.__buf->semmnu); printf("max number of semaphores per semid is %d /n", arg.__buf->semmsl); printf("max number of ops per semop call is %d /n", arg.__buf->semopm); printf("max number of undo entries per process is %d /n", arg.__buf->semume); printf("the sizeof of struct sem_undo is %d /n", arg.__buf->semusz); printf("the maximum semaphore value is %d /n", arg.__buf->semvmx);
//now ask for available resource: askfor_res.sem_num=0; askfor_res.sem_op=-1; askfor_res.sem_flg=SEM_UNDO;
if(semop(semid,&askfor_res,1)==-1)//ask for resource perror("semop error");
sleep(3); //do some handling on the sharing resource here, just sleep on it 3 seconds printf("now free the resource/n");
//now free resource free_res.sem_num=0; free_res.sem_op=1; free_res.sem_flg=SEM_UNDO; if(semop(semid,&free_res,1)==-1)//free the resource. if(errno==EIDRM) printf("the semaphore set was removed/n"); //you can comment out the codes below to compile a different version: if(semctl(semid, 0, IPC_RMID)==-1) perror("semctl IPC_RMID"); else printf("remove sem ok/n"); }
owner's uid is 0 owner's gid is 0 creater's uid is 0 creater's gid is 0 the number of entries in semaphore map is 32000 max number of semaphore identifiers is 128 mas number of semaphores in system is 32000 the number of undo structures system wide is 32000 max number of semaphores per semid is 250 max number of ops per semop call is 32 max number of undo entries per process is 32 the sizeof of struct sem_undo is 20 the maximum semaphore value is 32767 now free the resource remove sem ok
/*系统中的每个信号灯集对应一个sem_array 结构 */ struct sem_array { struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */ time_t sem_otime; /* last semop time */ 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 long sem_nsems; /* no. of semaphores in array */ };
其中,sem_queue结构如下:
/* 系统中每个因为信号灯而睡眠的进程,都对应一个sem_queue结构*/ struct sem_queue { struct sem_queue * next; /* next entry in the queue */ struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */ struct task_struct* sleeper; /* this process */ struct sem_undo * undo; /* undo structure */ int pid; /* process id of requesting process */ int status; /* completion status of operation */ struct sem_array * sma; /* semaphore array for operations */ int id; /* internal sem id */ struct sembuf * sops; /* array of pending operations */ int nsops; /* number of operations */ int alter; /* operation will alter semaphore */ };
附录2:union semun是系统调用semctl中的重要参数:
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 */ //test!! void *__pad; }; struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem; };