zoukankan      html  css  js  c++  java
  • linux进程间通信--信号量

    信号灯(信号量)集

    在多任务操作系统环境下,多个进程或线程会同时运行,多个任务可能可能为了完成同一个目标会相互协作,这样形成任务之间的同步关系;同样,在不同任务之间为了争夺有限的系统资源(硬件或软件资源)会进入竞争状态,这就是任务之间的互斥关系

    任务之间的同步与互斥关系存在的根源在于临界资源。临界资源是指同一个时刻只允许有限个(通常只有一个)任务可以访问(读)或修改(写)的资源,通常包括硬件资源和软件资源,访问临界资源的代码称为临界区

    POSIX 线程中的同步用的是无名信号量
    进程间的同步使用的是IPC 对象[信号灯集]

    信号灯集:信号灯集合,每一个信号灯都可以用来表示一类资源,其值表示资源的个数

    其中信号量(信号灯集)对应于某一种资源,取一个非负整数值,信号量值指的是当前可用的资源数量,若它为0这意味着目前没有可用的资源

    1.获得key值

    第一种:
      key_t ftok(const char *pathname, int proj_id);
    参数:
    @pathname 已经存在的文件路径
    @proj_id 获取这个整数的低8bit
    返回值:
      成功返回 key值,失败返回-1


    第二种:
    将key值指定为IPC_PRIVATE ,当IPC对象在亲缘关系进程间通信的时候

    (1)创建信号灯集
    int semget(key_t key, int nsems, int semflg);
    参数:
    @key IPC_PRIVATE , ftok()
    @nsems 信号灯集中信号灯的个数 
    @semflg IPC_CREAT | 0666,IPC_CREAT | IPC_EXCL
    返回值:
    成功返回ID,失败返回-1

    (2)初始化信号灯集中信号灯的值

    int semctl(int semid, int semnum, int cmd, union semun arg);
    参数:
    @semid 信号灯集的ID
    @semnum 信号灯的编号[编号从0开始]
    @cmd SETVAL[设置信号灯的值] ,GETVAL(获取信号灯的值),IPC_RMID[删除信号灯集]
    返回值:
    成功返回0,失败返回-1

    思考:将信号灯集中的1号信号灯初始化为1?

    其中arg:是union semnum 结构,可能在某些系统中不给出改结构的定义,这时必须由程序员自己定义

    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(Linux-specific) */
    };

    //初始化指定编号的sem_num信号灯集为value

    void init_sem_value(int sem_id,int sem_num,int value)
    {
      union semun sem_val;

      sem_val.val = value;

    if(semctl(sem_id,sem_num,SETVAL,sem_val) < 0)
    {
    ...
    }

    return ;
    }

    PV原子操作的具体定义:

    P操作:如果有可用资源(信号量值大于0),则占用一个资源(信号量值减一,进入临界区代码);如果没有可用资源(信号值等于0),则被阻塞,直到系统将资源分配给该任务(进入等待队列,一直等到有资源时被唤醒)

    V操作:如果该信号量在等待队列中有任务在等待资源,则唤醒一个阻塞任务,如果没有任务等待他,则释放一个资源(信号量值加1)

    (3)PV操作
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    功能: 完成PV操作
    参数:
     @semid 信号灯集的ID
     @sops 操作方式结构体首地址
     @nsops 操作信号灯的个数
    返回值:
    成功返回0,失败返回-1

    struct sembuf
    {
    unsigned short sem_num; /* semaphore number  ,信号量的编号,使用单个信号量时,通常取值为0*/
    short sem_op; /* semaphore operation  信号量操作,取-1表示P操作,取+1表示V操作*/
    short sem_flg; /* operation flags 通常设置为SEM_UNDO,这样在进程没有释放信号量退出时,系统会自动释放该进程中未释放的信号量 */
    };

    sem_op :
    <1>0 等待信号灯的值变成0
    <2>1 释放资源,V操作
    <3>-1 申请资源,P操作

    sem_flg:
    0 : 阻塞方式
    IPC_NOWAIT : 非阻塞方式调用
    SEM_UNDO : 进程结束的时候,它申请的资源自动释放

    -----------------------------------------------------------------

    P/V操作封装如下:
    void P(int sem_id,int sem_num)
    {
      struct sembuf sem;

      sem.sem_num = sem_num;
      sem.sem_op = -1;
      sem.sem_flg = 0;

      if(semop(sem_id,&sem,1) < 0)
      {
        ....
      }
    }

    void V(int sem_id,int sem_num)
    {
      struct sembuf sem;

      sem.sem_num = sem_num;
      sem.sem_op = 1;
      sem.sem_flg = 0;

      if(semop(sem_id,&sem,1) < 0)
      {
      ....
      }
    }

  • 相关阅读:
    c19---指针和字符串
    c18---数组和指针
    c17---指针
    c16---字符串
    c15--二位数组
    Android -- Properties使用
    四种更新UI的方法
    Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果
    Android 性能优化之使用MAT分析内存泄露
    android中PopupMenu的使用
  • 原文地址:https://www.cnblogs.com/bwbfight/p/9293330.html
Copyright © 2011-2022 走看看