美文网首页
Linux系统编程6:信号量

Linux系统编程6:信号量

作者: jdzhangxin | 来源:发表于2018-04-30 09:10 被阅读77次

    0. 信号量

    • 背景
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(int argc,char * argv[]){
     
        fork();
        int i=0;
        for(;i<5;i++){
            printf("PID:%d,enter\n",getpid());
            sleep(1);// do something
            printf("PID:%d,do something\n",getpid());
            printf("PID:%d,leave\n",getpid());
        }
    }
    

    数据竞争

    • 来源


    • 分类

    根据共享资源的数目可分为二值信号量和计数信号量两类。

    No. 分类 取值 e.g.
    1 二值信号量 01 指示锁
    2 计数信号量 0n 停车场电子牌
    指示锁 停车场电子指示牌 信号量
    • 作用
      控制多进程共享资源的访问(资源有限并且不共享)

    • 信号

    No. 分类 取值
    1 P(信号量) 0:挂起进程;>0:减1
    2 V(信号量) 0:恢复进程;>0:加1
    • 本质
      任一时刻只能有一个进程访问临界区(代码),数据更新的代码。

    1. POSIX 信号量

    • 资料:unpv22e-ch10.1~10.13
    • 查看:man sem_overview

    1.1 接口

    • 头文件:semaphore.h

    • 库:pthread

    • 分类
      信号量分为命名信号量(基于文件)与匿名信号量(基于内存)两种。

    1.2 函数

    1.2.1 命名信号量/基于文件

    No. 操作 函数
    1 创建 sem_t *sem_open(const char *name, int oflag, mode_t mode,unsigned int value)
    2 删除 int sem_unlink(const char *name)
    3 打开 sem_t *sem_open(const char *name, int oflag)
    4 关闭 int sem_close(sem_t *sem)
    5 挂出 int sem_post(sem_t *sem)
    6 等待 int sem_wait(sem_t *sem)
    7 尝试等待 int sem_trywait(sem_t *sem)
    8 获取信号量的值 int sem_getvalue(sem_t *sem, int *sval)
    1.2.1.1 创建
    sem_t *sem_open(const char *name, int oflag, mode_t mode,unsigned int value)
    
    • 参数
    No. 参数 含义
    1 name 信号量IPC名字
    2 oflag 标志
    3 mode 权限位
    4 value 信号量初始值

    IPC名字有什么要求?

    • 返回值
    No. 返回值 含义
    1 SEM_FAILED 信号量的指针
    2 SEM_FAILED 出错
    • 示例
    1.2.1.2 删除
    int sem_unlink(const char *name)
    
    • 参数
    No. 参数 含义
    1 name 信号量IPC名字
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.1.3 打开
    sem_t *sem_open(const char *name, int oflag)
    
    • 参数
    No. 参数 含义
    1 name 信号量IPC名字
    2 oflag 标志
    • 返回值
    No. 返回值 含义
    1 SEM_FAILED 信号量的指针
    2 SEM_FAILED 出错
    1.2.1.4 关闭
    int sem_close(sem_t *sem)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.1.5 挂出
    int sem_post(sem_t *sem)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.1.6 等待
    int sem_wait(sem_t *sem)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.1.7 尝试等待
    int sem_trywait(sem_t *sem)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.1.8 获取信号量的值
    int sem_getvalue(sem_t *sem, int *sval)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    2 sval 信号量的值
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    数据竞争解决方法

    上面竞争可以使用信号量解决。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <semaphore.h>
     
    int main(int argc,char * argv[]){
     
        sem_t* sem = sem_open("/sem.tmp",O_CREAT|O_RDWR,0644,1);
        fork();
        int i=0;
        for(;i<5;i++){
            sleep(1);
            sem_wait(sem);
            printf("PID:%d,enter\n",getpid());
            printf("PID:%d,do something\n",getpid());
            printf("PID:%d,leave\n",getpid());
            sem_post(sem);
        }
    }
    

    1.2.2 匿名信号量/基于内存

    No. 操作 函数
    1 初始化 int sem_init (sem_t *sem , int pshared, unsigned int value)
    2 销毁 int sem_destroy(sem_t *sem)
    3 挂出 int sem_post(sem_t *sem)
    4 等待 int sem_wait(sem_t *sem)
    5 尝试等待 int sem_trywait(sem_t *sem)
    6 获取信号量的值 int sem_getvalue(sem_t *sem, int *sval)

    其中3~4操作与命名信号量相同。

    1.2.2.1 初始化
    int sem_init (sem_t *sem , int pshared, unsigned int value)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    2 pshared 共享方式。0:线程间共享;1:进程间共享,需要共享内存
    3 value 信号量初始值
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    1.2.2.2 销毁
    int sem_destroy(sem_t *sem)
    
    • 参数
    No. 参数 含义
    1 sem 信号量的指针
    • 返回值
    No. 返回值 含义
    1 -1 出错
    2 0 成功
    数据竞争解决方法
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <semaphore.h>
     
    int main(int argc,char * argv[]){
     
        sem_t* sem = sem_open("/sem.tmp",O_CREAT|O_RDWR,0644,0);
        fork();
        int i=0;
        for(;i<5;i++){
            sleep(1);
            sem_wait(sem);
            printf("PID:%d,enter\n",getpid());
            printf("PID:%d,do something\n",getpid());
            printf("PID:%d,leave\n",getpid());
            sem_post(sem);
        }
    }
    

    小结

    命名信号量与匿名信号量

    案例

    模拟一个停车场的电子显示牌

    • park.cpp
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <semaphore.h>
     
    int main(int argc,char * argv[]){
        sem_t* sem = sem_open(argv[1],O_CREAT,0644,atoi(argv[2]));
    }
    
    • car.cpp
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <semaphore.h>
     
    void handler(int sig){
        printf("PID:%d,prepare to leave\n",getpid());
    }
     
    int main(int argc,char * argv[]){
        signal(SIGINT,handler);
        sem_t* sem = sem_open(argv[1],O_RDWR);
        sem_wait(sem);
        int val;
        sem_getvalue(sem,&val);
        printf("PID:%d,enter. park %d\n",getpid(),val);
        printf("PID:%d,do something\n",getpid());
        pause();
        sem_post(sem);
        sem_getvalue(sem,&val);
        printf("PID:%d,leave. park %d\n",getpid(),val);
    }
    
    • car_try.cpp
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <semaphore.h>
     
    void handler(int sig){
        printf("PID:%d,prepare to leave\n",getpid());
    }
     
    int main(int argc,char * argv[]){
     
        signal(SIGINT,handler);
     
        sem_t* sem = sem_open(argv[1],O_RDWR);
        if(-1 == sem_trywait(sem)){
            perror("no park");
            return 1;
        }
        int val;
        sem_getvalue(sem,&val);
        printf("PID:%d,enter. park %d\n",getpid(),val);
        printf("PID:%d,do something\n",getpid());
        pause();
        sem_post(sem);
        sem_getvalue(sem,&val);
        printf("PID:%d,leave. park %d\n",getpid(),val);
    }
    

    问题

    命名信号量与匿名信号量能否用于非亲缘线程?

    练习

    把信号量封装成一个信号量类

    相关文章

      网友评论

          本文标题:Linux系统编程6:信号量

          本文链接:https://www.haomeiwen.com/subject/jlrmhftx.html