linux 环境编程学习笔记 第25天 信号量(进程同步)


寒假学习 第25天 (linux 高级编程) 笔记总结

 

一、信号量(进程同步)


模型

(1)创建或者得到信号量     semget

       int semget(key_t key, 

                         int nsems, //信号量数组的个数

                          int semflg); ////信号量的创建标记   创建:IPC_CREAT  IPC_EXCL(防止重复创建),打开:就是0

(2)初始化信号量中指定下标的值      semctl

             int semctl(int semid,

                              int semnum, 

                              int cmd,//操作 SETVAL   IPC_RMID  如果是IPC_RMID则semnu跟 ... 都无意义

                               ...);

 

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

(3)根据信号量阻塞或者解除阻塞     semop

           int semop(int semid,  //共享信号量的ID

                           struct sembuf *sops,  //描述对信号量的操作,操作可以是数组

                           unsigned nsops); //第二个参数的个数(操作个数) (如果是两个操作,两个操作都会执行)

           struct sembuf成员:

                unsigned short sem_num;  //下标
                short          sem_op;  //负数 够减函数返回不阻塞,不够减阻塞  / 正数 /  0 判定信号量是否 > 0 ,>0则阻塞直到信号量为0
                short          sem_flg; //建议为0

       控制坚持到搭配方式:

            +(解除阻塞)     -(阻塞)

            0(阻塞)            -(解除阻塞)

(4)删除信号量       semctl

          semctl(semid,0,IPC_RMID);

例子1:

 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(int argc, const char *argv[])
{
    key_t key;
    int semid;
    key=ftok(".",22);
    if(key==-1) printf("ftok error:%m\n"),exit(-1);

    semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666);  //创建信号量

    if(semid==-1) printf("semget error:%m\n") ,exit(-1);

    return 0;
}


这样ipcs -s就会看到新增加的信号量

 

 

 

例子2:(用上面程序创建的信号量)

 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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


int main(int argc, const char *argv[])
{
    key_t key;
    int semid;
    key=ftok(".",22);
    if(key==-1) printf("ftok error:%m\n"),exit(-1);

    //semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666);
    //if(semid==-1) printf("semget error:%m\n") ,exit(-1);

    semid=semget(key,1,0);    //得到信号量
    if(semid==-1) printf("semget error:%m\n") ,exit(-1);

    printf("semid:%d\n",semid);

    union semun v; 
    v.val=2; //初始值为2
    
    int r;
    r=semctl(semid,0,SETVAL,v);   //设置信号量的值
    if(r==-1) printf("semctl error:%m\n"),exit(-1);

    //对信号量进行阻塞操作
    struct sembuf op[2]; // 定义操作,这里定义了两个操作
    op[0].sem_num=0; //信号量的下标
    op[0].sem_op=-1; //信号量的操作单位与类型  -就是阻塞(不够减就等待)
    op[0].sem_flg=0; //操作标记 IPC_NOWAIT不管够不够减都要返回,够减就是正常方式返回,不够减异常方式返回  SEM_UNDO当程序异常退出,系统自动把操作恢复到原始值,用来解除死锁。一般这两个都用不到

    while(1)
    {
        r=semop(semid,op,1); //val为2 执行2次就会阻塞
        printf("解除阻塞\n");
    }


    return 0;
}


输出两次“解除阻塞” 后阻塞

 

 

运行下面的程序 又可以开始输出"解除阻塞"

 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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


int main(int argc, const char *argv[])
{
    key_t key;
    int semid;
    key=ftok(".",22);
    if(key==-1) printf("ftok error:%m\n"),exit(-1);

    //semid=semget(key,1,IPC_CREAT|IPC_EXCL|0666);
    //if(semid==-1) printf("semget error:%m\n") ,exit(-1);

    semid=semget(key,1,0);    //得到信号量
    if(semid==-1) printf("semget error:%m\n") ,exit(-1);

    printf("semid:%d\n",semid);

    int r;
    
    //对信号量进行阻塞操作
    struct sembuf op[2]; // 定义操作,这里定义了两个操作
    op[0].sem_num=0; //信号量的下标
    op[0].sem_op=+1; //信号量的操作单位与类型  -就是阻塞(不够减就等待)
    op[0].sem_flg=0; //操作标记 IPC_NOWAIT不管够不够减都要返回,够减就是正常方式返回,不够减异常方式返回  SEM_UNDO当程序异常退出,系统自动把操作恢复到原始值,用来解除死锁。一般这两个都用不到

    while(1)
    {
        r=semop(semid,op,1); //val为2 执行2次就会阻塞
        sleep(1);
    }


    return 0;
}

 

 

 

  • 20519721

    评论: Good

    2017-09-16 20:04:46          回复

  • 20519721

    评论: Good

    2017-09-16 20:04:42          回复

  • django

    @root: 评论测试

    评论: 可以把评论也设置成支持markdown

    2017-08-27 19:51:35          回复

  • django

    评论: MARKDOWM测试 ``` SHSIAHOFAO ```

    2017-08-27 19:50:59          回复

  • root

    评论: 评论测试

    2017-04-06 17:02:45          回复

  • okidy90

    @10132405: 赞!

    评论: 6

    2017-01-10 23:00:19          回复

  • 10132405

    评论: 赞!

    2016-12-29 19:01:25          回复