• 进程间通信—System V-信号量


    进程间通信——信号量(信号灯)

      

      信号与信号量

      信号:是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常,是一种处理异步事件的方式。

      信号量:是一个特殊的变量,本质是计数器,记录了临界资源的数量。进程对其访问都是原子操作(PV操作),用于多线程、多进程之间同步临界资源。

      信号量分类

      按实现方式,信号量可以分为POSIX信号量与System V信号量。(POSIX与System V使用区别)

      System V信号量是基于内核维护的,,通常用于Linux系统中。Posix是由文件系统中的路径名对应的名字来标识的。

      在多线程中使用的基本是POSIX标准提供的接口函数,而多进程则是基于System V

    多线程使用System V接口---不建议。线程相对于进程是轻量级的,例如调度的策略开销,如果使用System V这种每次调用都会陷入内核的接口,会丧失线程的轻量优势。所以,多线程之间的通信不使用System V的接口函数。
    
    
           多进程使用POSIX也是允许的
    
         以mutex为例 ,POSIX的mutex如果要用于多进程,需要实现如下两点要求:(对于SEM信号量相对简单,因为提供了有名SEM的能够用于多进程,它是内核持续的,详见http://blog.csdn.net/firstlai/article/details/50706243)
    为何不建议System V信号量-多线程

      基于内存的信号量,同步多线程时,可放到该多线程所属进程空间里;如果是同步多进程,那就要把信号量放入到共享内存中(方便多个进程访问)。

         System V 信号量使用步骤

    1 打开/创建信号量   semget
    2 信号量初始化     semctl
    3 P/V操作         semop
    4 删除信号量       semctl

      1、信号量创建/打开---semget

    1 #include <sys/ipc.h>
    2 #include <sys/sem.h>
    3 
    4 int semget(key_t key, int nsems, int semflg);
    5 //成功返回信号量id,失败返回-1
    6 //参数
    7 //key---和消息队列关联的key, IPC_PRIVATE或ftok
    8 //nsems---集合中包含计数信号量个数
    9 //semflg---标志位, IPC_CREAT|0666  IPC_EXCL

      2、信号量初始化---semctl

     1 #include <sys/ipc.h>
     2 #include <sys/sem.h>
     3 
     4 int semctl(int semid, int semnum, int cmd, ...);
     5 
     6 //成功返回0,失败返回EOF
     7 //semid---要操作的信号量集的id
     8 //semnum---要操作的集合中的信号量编号
     9 //cmd---执行的操作  SETVAL  IPC_RMID
    10 //union semun---联合体,取决于cmd

      union semun

    1 union semun {
    2      int               val;   //SETVAL的值 
    3      struct semid_ds  *buf;   //Buffer for IPC_STAT, IPC_SET      
    4      unsigned short *array;   //Array for GETALL, SETALL
    5      struct seminfo   *_buf;  //Buffer for IPC_INFO
    6 }

      3、信号量P/V操作---semop

     1 #include <sys/ipc.h>
     2 #include <sys/sem.h>
     3 
     4 int semop(int semid, struct sembuf *sops, unsigned nsops);
     5 
     6 //成功返回0,失败EOF
     7 //参数
     8 //semid---要操作的信号量集的id
     9 //sops ---描述对信号量操作的结构体(数组)
    10 //nsops---要操作的信号量的个数
    11 
    12 struct sembuf{
    13      short sem_num;    //信号量编号
    14      short  sem_op;    //-1:P操作,1:V操作
    15      short  sem_flg;    //SEM_UNDO即0 ,IPC_NOWAIT
    16 }
      通常为SEM_UNDO即0,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量

    示例:信号量集/共享内存

    要求:父子进程通过System V信号量同步对共享内存的读写

       父进程从键盘输入字符串

       子进程输出字符串

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <errno.h>
      6 #include <sys/sem.h>
      7 #include <string.h>
      8 
      9 union semun{
     10     int val;
     11 }
     12 
     13 #define SEM_READ 0
     14 #define SEM_WRITE 0
     15 
     16 //实现P操作
     17 poperation(int index, int semid) //传入要操作的信号量,信号量集
     18 {
     19     //初始化sembuf结构体
     20     struct sembuf sop;
     21     sop.sem_num = index; //信号量编号
     22     sop.sem_op  = -1;    //P操作:-1
     23     sop.sem_flg =  0;    //SEM_UNDO
     24 
     25     //信号量集ID,对信号量操作的结构体,操作的信号量个数
     26     semop(semid,&sop,1);
     27 }
     28 
     29 voperation(int index, int semid)
     30 {
     31     //初始化sembuf结构体
     32     struct sembuf sop;
     33     sop.sem_num = index; //信号量编号
     34     sop.sem_op  =  1;    //V操作:1
     35     sop.sem_flg =  0;    //SEM_UNDO
     36 
     37     //信号量集ID,对信号量操作的结构体,操作的信号量个数
     38     semop(semid,&sop,1);
     39 
     40 }
     41 
     42 int main()
     43 {
     44     key_t key;
     45     int semid; //信号量集ID
     46     int shmid; //共享内存ID
     47     char * shmaddr;
     48     pid_t pid;
     49 
     50     key = ftok(".",123); //创建key键值,进而生成不同的IPC对象的标识符ID
     51 
     52     //创建2个信号量
     53     semid = semget(key, 2, IPC_CREAT|0777);
     54     if(semid < 0)
     55     {
     56         perror("semid");
     57         return -1;
     58     }
     59 
     60     //创建共享内存
     61     shmid = shmget(key, 256, IPC_CREAT|0777);
     62     if(shmid < 0)
     63     {
     64         perror("shmget");
     65         return -1;
     66     }
     67 
     68     //初始化2个信号量
     69     union semun myun;
     70     myun.val = 0; //初始化读信号量的值为0,未读
     71     semctl(semid, SEM_READ, SETVAL, myun);
     72 
     73     myun.val = 1; //初始化写信号量的值为1,可写
     74     semctl(semid, SEM_WRITE,SETVAL, myun);
     75 
     76     //创建一个子进程
     77     pid = fork();
     78     if(pid < 0)
     79     {
     80         perror("fork");
     81         return -1;
     82     }
     83     else if(pid == 0) //子进程
     84     {
     85         //获取映射后的共享内存的地址
     86         shmaddr = (char *)shmat(shmid, NULL, 0);
     87         
     88         poperation(SEM_READ,semid); //读之前对读信号量进行P操作
     89 
     90         printf("getshm:%s",shmaddr);
     91 
     92         voperation(SEM_WRITE,semid); //V操作,读完了,告诉父进程可写
     93 
     94     }else{ //父进程从键盘输入字符
     95 
     96         //获取映射后的共享内存的地址
     97         shmaddr = (char *)shmat(shmid, NULL, 0);
     98         
     99         poperation(SEM_WRITE,semid); //写之前对写信号量进行P操作
    100 
    101         printf("Please input char to shm:");
    102         fgets(shmaddr, 32,stdin);
    103 
    104         voperation(SEM_READ,semid); //V操作,写完,告诉子进程可以读
    105     }
    106 
    107 
    108 }

    结果:

    【信号量的意图在于进程间同步,互斥锁和条件变量的意图则在于线程间同步。但是信号量也可用于线程间,互斥锁和条件变量也可用于进程间。我们应该使用适合具体应用的那组原语。】--------https://www.cnblogs.com/fangshenghui/p/4039946.html

  • 相关阅读:
    hdu 5400 Arithmetic Sequence
    【小超_Android】android上开源的酷炫的交互动画和视觉效果:Interactive-animation
    项目PMO工作
    HDU 3340 Rain in ACStar(线段树+几何)
    再看数据库——(6)连接
    Android 安装应用后点击打开带来的问题
    Notes 和 Domino 已知限制
    去哪网实习总结:JavaWeb配置404页面(JavaWeb)
    Android 怎样实现 焦点图的 无线循环滑动的状态?
    【JNI探索之路系列】之七:JNI要点总结
  • 原文地址:https://www.cnblogs.com/y4247464/p/12115743.html
Copyright © 2020-2023  润新知