13--信号量,共享内存和消息队列

来源:互联网 发布:敏捷软件开发 pdf 编辑:程序博客网 时间:2024/05/22 20:40

进程间的通信

         (1) 基于文件的通信:

                            1. 普通文件(io/mmap)

                            2.有名管道文件

                            3.匿名管道文件

                            4.socket

       (2)基于内存的通信:

                            1.信号量 :用于管理对资源的访问。

                            2.共享内存:用于进程之间高校的地共享数据。

                             3.消息队列:在程序之间传递数据的一种简单方法。

使用到的命命令:

—————————————————————————

$ ipcs

$ ipcs -s    --------- 查看信号量

$ ipcs -m  ---------- 共享内存

$ ipcs -q   ----------- 消息队列

$ ipcrm -q 编号ID    ---------删除消息队列

——————————————————————————



一.信号量

1.semget函数

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>


       int semget(key_t key,  /// 为一个整数值,

                          int nsems,  //// 为信号量数目,通常取值为1.

                          int semflg);/// 一组标志,通常使用 IPC_CREAT | IPC_EXCL 来创建新的,唯一的信号量。

   说明:创建一个信号量,获得一个信号量ID。

              如果成功:

                               返回信号量标识符。

             如果失败:

                             返回-1.

2. semop函数

       int semop(int semid,   //// 有semget返回的信号量标识符。

                        struct sembuf *sops, ////指向结构体数组的指针

                       unsigned nsops);   ///

         说明: 用于改变信号量的值


第二个参数指向的结构体数组中,每个数组元素至少包含以下成员

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,
};

3. semctl 函数

         int semctl(int semid,    ///有semget返回的信号量标识符

                         int semnum,   /// 信号量编号,一般取值为0(表示是唯一信号量)

                         int cmd, ...);   ///   采取的行动

     说明: 直接控制信号量信息。

cmd有两个最常用的值:

   SETVAL: 用来把信号量初始化为一个已知的值。

  IPC_RMID:  用于删除一个已知无需继续使用的信号量标识符。

二.共享内存

1.shmget函数

         #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, /// ftok 函数可以取得唯一的key值

                         size_t size, /// 共享内存容量

                         int shmflg)/// 9个比特的权限标志

   说明: 创建共享内存,返回共享内存标识符。

第三个参数的常见两种方式:

     创建: (IPC_CREAT | IPC_EXCL)

     打开: 0

2.shmat 函数

       void *shmat(int shmid,/// 由shmget返回的共享内存标识符。

                            const void *shmaddr, ///

                               int shmflg);

       说明: 根据ID得到共享,访问内存数据。

3.shmdt函数

       int shmdt(const void *shmaddr);

      说明: 将共享内存从当前进程中分离,参数为shmat返回的地址指针。

4. shmctl 函数

       int shmctl(int shmid,    ///  shmget返回的共享内存标识符

                                int cmd,   ///  要采取的动作

                               struct shmid_ds *buf); /// 指向包含共享内存模式和访问权限的当前关联值

第二个参数cmd的可取值:

————————————————————————————

IPC_STAT    ------

IPC_SET      ------

IPC_RMID   --------删除共享内存段 


  第三个参数的struct  shmid_ds 结构体:

——————————————————————————————————

                 struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...

           };
——————————————————————————————————————

编程模型:
               (1)  创建共享内存,得到一个ID;

               (2)把ID映射成虚拟地址(挂载);

               (3)使用虚拟地址访问内核共享内存

               (4)卸载(分离)虚拟地址, shmdt

               (5) 删除共享内存    shctl(修改/获取共享内存的属性)

案例:
shmA.c

/// shmA.c#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <sys/shm.h>#include <sys/ipc.h>key_t  key;int shmid;int *p;int i = 0;void deal(int s){if(s==SIGINT){//4.卸载共享内存shmdtshmdt(p);//5.删除共享内存shctlshmctl(shmid,IPC_RMID,0);exit(0);}}main(){signal(SIGINT,deal);//1.创建共享内存, shmgetkey = ftok("/tmp",255);if(key == -1) printf("ftok error:%m\n"),exit(-1);shmid = shmget(key,4,IPC_CREAT | IPC_EXCL |0666);if(shmid == -1) printf("get error:%m\n"),exit(-1);//2.挂载共享内存shmatp = shmat(shmid,0,0);if(p == (int*)-1) printf("get error:%m\n"),exit(-1);//3.访问共享内存while(1){*p = i;sleep(1);++i;}}

shmB.c

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <sys/shm.h>#include <sys/ipc.h>key_t key;int shmid;int *p;void deal(int s){if(s==SIGINT){//4. 卸载共享内存, shmdtshmdt(p);exit(0);}}main(){signal(SIGINT,deal);//1.创建共享内存key = ftok("/tmp",255);if(key == -1) printf("ftok error:%m\n"),exit(-1);shmid = shmget(key,4,0);if(shmid == -1) printf("get error:%m\n"),exit(-1);//2.挂载共享内存shmatp = shmat(shmid,0,0);if(p == (int*)-1) printf("ar error:%m\n"),exit(-1);//3.访问共享内存while(1){sleep(1);printf("%d\n",*p);}}

补充:

——————————————————

$ ipcs -m  ------ 查看共享内存

$ ipcrm -m  555****(文件ID)   ------ 删除共享内存(这个文件ID是随机的)

三. 消息队列

       消息队列是在两个不相关进程之间传递数据的,优势是独立于发送和接收进程而存在

1. msgget函数-----------------创建消息队列函数

       int msgget(key_t key, int msgflg);

2. msgsnd函数-------------------发送消息

       int msgsnd(int msqid,  //// 消息队列标识符

                  const void *msgp, /// 要发送的消息

                  size_t msgsz,   //// 消息的长度

                  int msgflg);  ///// 发送消息的方式,建议为0


3.msgrcv函数 ---------------从消息队列中获取消息

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

4.msgctl 函数

       int msgctl(int msqid, int cmd, struct msqid_ds *buf);

编程模型:

       创建消息队列

       使用消息队列

       删除队列

//// msgA.c   发射部分#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/msg.h>#define MAX_TEXT 512struct msgbuf{long mtype;char mtext[MAX_TEXT];};int main(){int flag = 1;key_t key;struct msgbuf  msg;int msgid;char buffer[BUFSIZ];// 1.创建消息队列key = ftok(".",200);if(key == -1) printf("frok err:%m\n"),exit(-1);printf("key=%d\n",key);msgid = msgget(key,0666 | IPC_CREAT);if(msgid == -1) printf("msgget err:%m\n"),exit(-1);while(flag){printf("请输入您要发送的字符串(以“#”结束输入):\n");fgets(buffer,BUFSIZ,stdin);msg.mtype = 1;bzero(msg.mtext,sizeof(msg.mtext));strcpy(msg.mtext,buffer);if(msgsnd(msgid,&msg,MAX_TEXT,0) == -1) printf("msgsnd err:%m\n") ,exit(-1);if(strncmp(buffer,"#",1) == 0)flag = 0;}msgctl(msgid,IPC_RMID,0); // 删除队列exit(0);}

//// msgB.c  接收部分#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/msg.h>struct msgbuf{long mtype;char mtext[BUFSIZ];};int main(){int flag = 1;key_t key;int msgid;struct msgbuf msg;key = ftok(".",200);if(key == -1) printf("ftok err:%m\n"),exit(-1);printf("key=%d\n",key);msgid = msgget(key,0666 | IPC_CREAT);if(msgid == -1) printf("msgget err:%m\n"),exit(-1);while(flag){bzero(msg.mtext,sizeof(msg.mtext));if(msgrcv(msgid,(void *)&msg,BUFSIZ,0,0) == -1) printf("msgrcv err:%m\n"),exit(-1);printf("你接收到的数据是:%s\n",msg.mtext);if(strncmp(msg.mtext,"#",1) ==0 )flag = 0;}// 删除消息队列msgctl(msgid,IPC_RMID,0); }




0 0
原创粉丝点击