system V信号量

system V信号量:
这是信号量的集合,而不是单个信号量
相关的信号量操作函数由引用

一、信号量的数据结构:

Linux中信号量是通过内核提供的一系列数据结构实现的,这些数据结构存在于内核空间,对它们的分析是充分理解信号量及利用信号量实现进程间通信的基础,下面先给出信号量的数据结构(存在于include/linux/sem.h中),其它一些数据结构将在相关的系统调用中介绍。

  1. 系统中每个信号量的数据结构(sem)
    struct sem {
    
               int  semval;            /* 信号量的当前值  */
    
               int   sempid;          /*在信号量上最后一次操作的进程识别号 */
               
               ushort semncnt;       /*等待semval大于当前值的进程个数*/
    
               ushort semzcnt;      /*等待semval变成0的进程个数*/
     };
  2. 系统中表示信号量集合(set)的数据结构(semid_ds

    struct semid_ds {
    
                      struct ipc_perm sem_perm;          /*  IPC权限 */
    
                      long        sem_otime;        /* 最后一次对信号量操作(semop)的时间 */
    
                      long        sem_ctime;        /* 对这个结构最后一次修改的时间 */
    
                      struct sem      *sem_base;      /* 在信号量数组中指向第一个信号量的指针 */
    
                      struct sem_queue *sem_pending;       /* 待处理的挂起操作*/
    
                      struct sem_queue **sem_pending_last; /* 最后一个挂起操作 */
    
                      struct sem_undo *undo;          /* 在这个数组上的undo 请求 */
    
                      ushort          sem_nsems;           /* 在信号量数组上的信号量号 */
    
       };

  3. 系统中每个信号量集合的队列的数据结构(sem_queue)
    struct sem_queue {   
    
              struct sem_queue * next;   /* 队列中下一个节点 */
    
              struct sem_queue **    prev;   /* 队列中前一个节点, *(q->prev) == q */
    
              struct wait_queue *    sleeper;    /* 正在睡眠的进程 */
       
              struct sem_undo *  undo;   /* undo 结构*/
    
              int            pid;    /* 请求进程的进程识别号 */
    
              int            status; /* 操作的完成状态 */
     
              struct semid_ds *  sma;    /*有操作的信号量集合数组 */
    
              struct sembuf *    sops;   /* 挂起操作的数组 */
    
              int    nsops;  /* 操作的个数 */
    
    };

集中数据结构的重要关系见下图

从图中可知,操作这个信号量集合的进程,在系统调用下对信号量集合中的信号值进行操作。此处,注意信号量和信号的区别。

信号量是一个表述进程是否能拥有资源的关键值,信号量集合是一个包括指向要使用信号量的进程等待队列,其他控制信息以及信号量等信息的复杂的结构

信号量数据结构总体图

(本人错略画出来的不代表绝对的正确)


二、常见的system V 信号量函数

a)关键字和描述符

    system V信号量是system V IPC(即system V进程间通信)的组成部分,其他的有system V消息队列,system V共享内存

关键字和IPC描述符是它们的共同特点。


IPC描述符相当于引用ID号,要想使用system V信号(或MSG、SHM),就必须用IPC描述符来调用信号量。

而IPC描述符是内核动态提供的(通过semget()来获得),开发者无线让服务器和客户事先认可共同使用哪个

描述符,所以有时候就需要用到关键字KEY来定位描述符

一个key会关联固定一个对应的描述符(由内核完成),这样服务器和客户事先共享一个共同认可的key,则

就可以同时定位到同一信号的描述符上,这样即可达到system V信号量在进程间的共享

b) 创建和打开信号量

come from /usr/include/sys/sem.h 
/* Get semaphore. */ 
extern int semget (key_t __key, int __nsems, int __semflg) __THROW;


   1)指定创造信号中 信号的数量,一旦创建不可在修改

   2)__nsems值为0,则访问一个已存在的信号量集合

   3)__semflg打开方式

返回一个称为信号量标识符的整数,semctl和semop将使用它

创建成功后:

  • sem_perm的uid和gid成员被设置成调用进程的有限用户ID和有效组ID
  • semflg中的读写权限位存入sem_perm.mode位
  • sem_otime被置为0,sem_ctime被设置为当前时间
  • sem_nsems被设置为nsems参数的值

该集合中的信号量不初始化,信号量的初始化是在semctl函数用参数SETVAL和GETVAL实现的

setget()函数执行成功后,就会产生一个内核维持的类型为semid_ds结构体的信号量集,返回semid就是指向该信号量集的索引


c)关键字的获取

     有很多方法是客户机和服务器在同一IPC结构上回合:

  1. 服务器可以指定关键字IPC_PRIVATE创建一个新IPC结构,讲返回的标识符存放在某处(例如一个文件)以便客户机取用。关键字IPC_PRIVATE保证服务器创建一个新
    IPC结构。这种技术: 服务器要将整型标识符写到文件中,然后客户端又要读文件取得此标识符。
    IPC_PRIVATE关键字也可用于父子关系进程。父进程指定IPC_PRIVATE创建一个新IPC结构,所返回的标识符在fork后可由子进程时候,子进程可将此标识作为exec函数的一个参数传递给新的程序

  2. 在一个公用头文件中定义一个客户机和服务器都认可的关键字。然后服务器指定此关键字创建一个新的IPC结构。这种当打的问题是该关键字可能已与一个IPC结构相结合,在此情况下get函数(msgget、semget、shmget)出错返回,服务器必须处理这个错误,删除已存在的IPC结构,然后试着再创建它。当然这个关键字不能被别的进程占用。

  3. 客户机和服务器认同一个路径名和课题ID(课题DI是0 ~ 255之间的字符值),然后调用函数ftok将这两个值变换成一个关键字。这样就避免了使用一个已被占用的关键字问题。
    使用ftok并非高枕无忧。有这么一个特例:
    服务器ftok获取一个关键字后,该文件就被删除了,然后重建。此时客户端以此重建后的文件来fork所获得的关键字就和服务器的关键字不一样了。所以一般的商用软件
    都不怎么使用fork函数。
    一般来书,客户机和服务器至少共享一个头文件,所以一个比较简单的方法就是避免使用ftok,而只是在该头文件中存放一个大家都知道的关键字。

d)设置信号量的值(PV操作)

c)对信号集实行控制操作(semval的赋值等)

详见:http://blog.csdn.net/hailuoing/article/details/8219461

参考文章:
http://www.360doc.com/content/12/0824/12/8809247_232067949.shtml




你可能感兴趣的:(system V信号量)