#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> union semun{ int val; struct semid_ds *buf; unsigned short *array; }; static int set_semvalue(void); static void del_semvalue(void); static int semaphore_p(void); static int semaphore_v(void); static int sem_id; int main(int argc,char *argv[]) { int i; int pause_time; char op_char='O'; srand((unsigned int)getpid()); sem_id=semget((key_t)1234,1,0666 | IPC_CREAT); if(argc>1) { if(!set_semvalue()) { fprintf(stderr,"Failed to initialize semphore\n"); exit(EXIT_FAILURE); } op_char='X'; sleep(2); } for(i=0;i<10;i++) { if(!semaphore_p()) exit(EXIT_FAILURE); printf("%c",op_char); fflush(stdout); pause_time=rand()%3; sleep(pause_time); printf("%c",op_char); fflush(stdout); if(!semaphore_v()) exit(EXIT_FAILURE); pause_time=rand()%3; sleep(pause_time); } printf("\n%d - finished\n",getpid()); if(argc>1) { sleep(10); del_semvalue(); } exit(EXIT_SUCCESS); } static int set_semvalue(void) { union semun sem_union; sem_union.val=1; if(semctl(sem_id,0,SETVAL,sem_union)==-1) return (0); return (1); } static void del_semvalue(void) { union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union)==-1) fprintf(stderr,"Failed to delete semaphore\n"); } static int semaphore_p(void) { struct sembuf sem_b; sem_b.sem_num=0; sem_b.sem_op=-1; sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { fprintf(stderr,"semaphore_p failed\n"); return (0); } return (1); } static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num=0; sem_b.sem_op=1; sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { fprintf(stderr,"semaphore_v failed\n"); return (0); } return (1); }
用semget函数通过一个(随意选取的)键来取得一个信号量标识符。IPC_CREAT标志的作用是:如果信号量不存在,就创建它。
如果程序带有一个参数,它就负责信号量的初始化工作,这是通过set_semvalue函数来完成的,该函数是针对更通用的semctl函数的简化接口。程序还根据是否带有参数来决定需要打印哪个字符。sleep函数的作用是,让我们有时间在这个程序实例执行太多次循环之前调用其他的程序实例。
接下来程序循环10次,在临界区和非临界区会分别暂停一段随机的时间。临界区域由semaphore_p和semaphore_v函数前后把守,它们是更通用的semop函数的简化接口。
删除信号量之前,带有参数启动的程序会进入等待状态,以允许其他调用实例都执行完毕。