共享内存 信号灯集 消息队列

【1】共享内存:

  1. 特点:

    1. 共享内存是一种最为高效的进程间通信方式,
      进程可以直接读写内存,而不需要任何数据的拷贝
    2. 为了在多个进程间交换信息,内核专门留出了一块内存区,
      可以由需要访问的进程将其映射到自己的私有地址空间
    3. 进程就可以直接读写这一内存区而不需要进行数据的拷贝,
      从而大大提高的效率。
    4. 由于多个进程共享一段内存,因此也需要依靠某种同步机制,
      如互斥锁和信号量等
  2. 共享内存的使用步骤:

    1. 创建key值
      key_t key = ftok(路径,int)//key值打印出来:0x610191c8 01是系统编号
      //key("./app",'a')---a->0x61 app->1479112=0x191c8
    2. 创建或打开共享内存
      int shmid = shmget(key, size, IPC_CREAT|IPC_EXCL|0666);
    3. 映射共享内存到用户空间
      地址 = shmat(shmid, NULL, 0);
    4. 撤销映射
      shmdt(地址);
    5. 删除共享内存
      shmctl(shmid, IPC_RMID, NULL);
ipcs 
  1. 相关函数:
    1. key_t ftok(const char *pathname, int proj_id);
      功能:产生一个独一无二的key值
      参数:
      Pathname:已经存在的可访问文件的名字
      Proj_id:一个字符(因为只用低8位)
      返回值:成功:key
      失败:-1

    2. int shmget(key_t key, size_t size, int shmflg);
      功能:创建或打开共享内存
      参数:
      key 键值
      size 共享内存的大小
      shmflg IPC_CREAT|IPC_EXCL|0777
      返回值:成功 shmid
      出错 -1

    3. void *shmat(int shmid,const void *shmaddr,int shmflg);
      功能:映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
      参数:
      shmid 共享内存的id号
      shmaddr 一般为NULL,表示由系统自动完成映射
      如果不为NULL,那么有用户指定
      shmflgSHM_RDONLY就是对该共享内存只进行读操作shm_rdonly
      0 可读可写
      返回值:成功:完成映射后的地址,
      出错:-1地址
      用法:if((p = (char *)shmat(shmid,NULL,0)) == (char *)-1)

    4. int shmdt(const void *shmaddr);
      功能:取消映射
      参数:要取消的地址
      返回值:成功0
      失败的-1

    5. int shmctl(int shmid,int cmd,struct shmid_ds *buf);
      功能:(删除共享内存),对共享内存进行各种操作
      参数:
      shmid 共享内存的id号
      cmd :IPC_STAT获得shmid属性信息,存放在第三参数
      IPC_SET 设置shmid属性信息,要设置的属性放在第三参数
      IPC_RMID:删除共享内存,此时第三个参数为NULL即可
      返回: 成功0
      失败-1
      用法:shmctl(shmid,IPC_RMID,NULL);

查看共享内存的命令:`ipcs -m`
删除共享内存的命令:`ipcrm -m [shmid]	 `

【2】信号灯集:

  1. 特点:
    信号灯(semaphore),也叫信号量。它是不同进程间
    或一个给定进程内部不同线程间同步的机制
    System V的信号灯是一个或者多个信号灯的一个集合。
    其中的每一个都是单独的计数信号灯。而Posix信号
    灯指的是单个计数信号灯

  2. 信号灯种类:
    posix有名信号灯
    posix基于内存的信号灯(无名信号灯)
    System V信号灯(IPC对象)

  3. 创建步骤:
    0. 创建key
    ftok
    1. 创建或打开信号灯集
    semid = semget(key, num, flag);
    2. 初始化信号灯
    semctl(semid, 编号, SETVAL, union semun);
    3. PV操作
    semop(semid, struct sembuf, 1);
    4. 删除信号灯集
    semctl(semid, 0, IPC_RMID);

  4. 相关函数:

    1. int semget(key_t key, int nsems, int semflg);
      功能:创建/打开信号灯
      参数:keyftok产生的key
      nsems:信号灯集中包含的信号灯数目
      semflg:信号灯集的访问权限,通常为IPC_CREAT|IPC_EXCL|0666
      返回值:成功:信号灯集ID
      失败:-1

    2. int semop ( int semid, struct sembuf *opsptr, size_t nops);
      功能:对信号灯集合中的信号量进行PV操作
      参数:semid:信号灯集ID
      struct sembuf {
      short sem_num; // 要操作的信号灯的编号
      short sem_op;
      // 0 : 等待,直到信号灯的值变成0
      // 1 : 释放资源,V操作
      // -1 : 申请资源,P操作
      short sem_flg;
      // 0(阻塞),IPC_NOWAIT, SEM_UNDO
      };

      nops: 要操作的信号灯的个数 1个
      返回值:成功 :0
      失败:-1
      用法:

      1. 申请资源 P操作:
        mysembuf.sem_num = 0;
        mysembuf.sem_op = -1;
        mysembuf.sem_flg = 0;
        semop(semid, &mysembuf, 1);
      2. 释放资源 V操作:
        mysembuf.sem_num = 0;
        mysembuf.sem_op = 1;
        mysembuf.sem_flg = 0;
        semop(semid, &mysembuf, 1);
    3. int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);
      功能:信号灯集合的控制(初始化/删除)
      参数:semid:信号灯集ID
      semnum: 要操作的集合中的信号灯编号
      cmd
      GETVAL:获取信号灯的值,返回值是获得值
      SETVAL:设置信号灯的值(资源量),
      需要用到第四个参数:共用体
      IPC_RMID:从系统中删除信号灯集合
      返回值:成功 0
      失败 -1
      用法:

      1. 初始化:
        union semun{
        int val;
        }mysemun;
        mysemun.val = 10;
        semctl(semid, 0, SETVAL, mysemun);
      2. 获取信号灯值:函数semctl(semid, 0, GETVAL)的返回值
      3. 删除信号灯集:semctl(semid, 0, IPC_RMID);
查看信号灯集的命令:ipcs -s
删除信号灯集的命令:ipcrm -s [semid]

【3】消息队列

  1. 特点:
    消息队列是IPC对象的一种
    消息队列由消息队列ID来唯一标识
    消息队列就是一个消息的列表。用户可以在消息队列
    中添加消息、读取消息等。
    消息队列可以按照类型来发送/接收消息
  2. 步骤:
    1. 产生keyftok
    2. 创建或打开消息队列
    3. 添加消息:按照类型把消息添加到已打开的消息队列末尾
    4. 读取消息:可以按照类型把消息从消息队列中取走
    5. 删除消息队列
  3. 相关函数:
    1. int msgget(key_t key, int flag);
      功能:创建或打开一个消息队列
      参数:key
      flag:创建消息队列的权限IPC_CREAT|IPC_EXCL|0666
      返回值:成功:msgid
      失败:-1

    2. int msgsnd(int msqid, const void *msgp, size_t size, int flag);
      功能:添加消息
      参数:msqid:消息队列的ID
      msgp:指向消息的指针。常用消息结构msgbuf如下:
      struct msgbuf{
      long mtype; //消息类型
      char mtext[N];
      }; //消息正文
      size:发送的消息正文的字节数
      flagIPC_NOWAIT消息没有发送完成函数也会立即返回
      0:直到发送完成函数才返回
      返回值:成功:0
      失败:-1
      使用:msgsnd(msgid, &msg,sizeof(msg)-sizeof(long), 0)
      注意:消息结构除了第一个成员必须为long类型外,其他成员可以根据应用的需求自行定义。

    3. int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag);
      功能:读取消息
      参数:msgid:消息队列的ID
      msgp:存放读取消息的空间
      size:接受的消息正文的字节数
      msgtype
      0:接收消息队列中第一个消息。
      大于0:接收消息队列中第一个类型为msgtyp的消息.
      小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。
      flag0:若无消息函数会一直阻塞
      IPC_NOWAIT:若没有消 息,进程会立即返回E NO MSG
      返回值:成功:接收到的消息的长度
      失败:-1

    4. int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
      功能:对消息队列的操作,删除消息队列
      参数:msqid:消息队列的队列ID
      cmd
      IPC_STAT:读取消息队列的属性,并将其保存在
      buf指向的缓冲区中。
      IPC_SET:设置消息队列的属性。这个值取自buf参数。
      IPC_RMID:从系统中删除消息队列。
      buf:消息队列缓冲区
      返回值:成功:0
      失败:-1
      用法:msgctl(msgid, IPC_RMID, NULL)

  • 补充:线程池
    创建线程时,需要分配一个PCB,但是不用分配地址空间。
    创建进程不仅需要分配一个PCB,还需要分配一个地址空间,还得占用cpu资源。
    一下创建多个线程放在一个池子中,让所有的线程阻塞,不占用cpu资源,什么时候
    需要用的时候再进行唤醒使用。用完后又让他阻塞,减少频繁创建进程申请资源和
    释放资源–》eg:一个网页打开,就会有很多的请求,有了请求我们创建一个线程使用。
    PCB:进程控制块

你可能感兴趣的:(linux,c,数据库)