进程间通信之信号量semaphore--linux内核剖析( 七 )

  • 客户机和服务器认同一个路径名和课题I D(课题I D是0 ~ 2 5 5之间的字符值), 然后调用函数ftok将这两个值变换为一个关键字 。 这样就避免了使用一个已被占用的关键字的问题 。使用ftok并非高枕无忧 。 有这样一种例外:服务器使用ftok获取得一个关键字后 , 该文件就被删除了 , 然后重建 。 此时客户端以此重建后的文件来ftok所获取的关键字就和服务器的关键字不一样了 。 所以一般商用的软件都不怎么用ftok 。一般来说 , 客户机和服务器至少共享一个头文件 , 所以一个比较简单的方法是避免使用ftok , 而只是在该头文件中存放一个大家都知道的关键字 。
  • 设置信号量的值(PV操作)int semop(int semid, struct sembuf *opsptr, size_t nops);参数描述semid是semget返回的semid信号量标示符opsptr指向信号量操作结构数组nopsopsptr所指向的数组中的sembuf结构体的个数
    该函数执行成功返回0 , 失败返回-1;
    第二个参数sops为一个结构体数组指针 , 结构体定义在sys/sem.h中 , 结构体如下
    struct sembuf {unsigned short sem_num; /* semaphore index in array */short sem_op; /* semaphore operation */short sem_flg; /* operation flags */};sem_num 操作信号的下标 , 其值可以为0 到nops sem_flg为该信号操作的标志:其值可以为0、IPC_NOWAIT 、 SEM_UNDO
    sem_flg标识描述0在对信号量的操作不能执行的情况下 , 该操作阻塞到可以执行为止;IPC_NOWAIT在对信号量的操作不能执行的情况下 , 该操作立即返回;SEM_UNDO当操作的进程推出后 , 该进程对sem进行的操作将被取消;
    sem_op取值描述>0>0则信号量加上它的值 , 等价于进程释放信号量控制的资源=0=0若没有设置IPC_NOWAIT ,那么调用进程将进入睡眠状态 , 直到信号量的值为0 , 否则进程直接返回则信号量加上它的值 , 等价于进程申请信号量控制的资源 , 若进程设置IPC_NOWAIT则进程再没有可用资源情况下 , 进程阻塞 , 否则直接返回 。
    例如 , 当前semval为2 , 而sem_op = -3 , 那么怎么办?
    注意:semval是指semid_ds中的信号量集中的某个信号量的值
    #include #include #include #include #include int main(int argc,char *argv[]){intc,i,flag,semid,nops;structsembuf *ptr;flag = 0;//根据命令行参数设置操作模式while( ( c = getopt(argc,argv,"nu")) != -1){switch(c){case 'n':flag |= IPC_NOWAIT;//非阻塞break;case 'u':flag |= SEM_UNDO;//不可恢复break;}}if(argc - optind < 2){printf("usage: semops [-n] [-u]operation...");exit(0);}//打开一个已经存在的信号量集合if((semid = semget(ftok(argv[optind],0),0,0)) == -1){perror("semget() error");exit(-1);}optind++;//指向当前第一个信号量的位置nops = argc - optind;//信号量个数ptr = calloc(nops,sizeof(struct sembuf));for(i=0;i对信号集实行控制操作(semval的赋值等)int semctl(int semid, int semum, int cmd, ../* union semun arg */);参数描述semid是信号量集合;semnum是信号在集合中的序号;semum是一个必须由用户自定义的结构体 , 在这里我们务必弄清楚该结构体的组成:
    union semun{int val; // cmd == SETVALstruct semid_ds *buf // cmd == IPC_SET或者 cmd == IPC_STATushort *array; // cmd == SETALL , 或 cmd = GETALL};值描述IPC_STAT读取一个信号量集的数据结构semid_ds , 并将其存储在semun中的buf参数中 。 IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm , 其值取自semun中的buf参数 。 IPC_RMID将信号量集从系统中删除GETALL用于读取信号量集中的所有信号量的值 , 存于semnu的array中SETALL设置所指定的信号量集的每个成员semval的值GETPID返回最后一个执行semop操作的进程的PID 。 LSETVAL把的val数据成员设置为当前资源数GETVAL把semval中的当前值作为函数的返回 , 即现有的资源数 , 返回值为非负数 。
    val只有cmd ==SETVAL时才有用 , 此时指定的semval = arg.val 。
    注意:当cmd == GETVAL时 , semctl函数返回的值就是我们想要的semval 。 千万不要以为指定的semval被返回到arg.val中 。
    array指向一个数组 ,
    当cmd==SETALL时 , 就根据arg.array来将信号量集的所有值都赋值;
    当cmd ==GETALL时 , 就将信号量集的所有值返回到arg.array指定的数组中 。
    buf 指针只在cmd==IPC_STAT 或IPC_SET 时有用 , 作用是semid 所指向的信号量集
    (semid_ds机构体) 。 一般情况下不常用 , 这里不做谈论 。
    另外 , cmd == IPC_RMID还是比较有用的 。