4.进程通信

1.消息队列

  在终端查询消息队列  ipcs -q

  在终端删除消息队列  ipcrm -q 队列ID号 {ipcrm -q key 键值}

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

  (1)获取键值key  --通过文件路径,加上proj_id组合生成键值key

key_t ftok(const char *pathname, int proj_id);

    参数:pathname文件路径--文件路径必须存在   /home/gec

             int proj_id---使用小于128的数据   100

              一般写成key_t key = ftok(“pathname”,100);

  (2)获取消息队列

int msgget(key_t key, int msgflg);

    参数:key_t key---键值

           int msgflg ————相当与open函数里面的O_CREAT ---IPC_CREAT|权限

    返回值:返回消息队列的id号,失败返回-1

    一般写成int msgid – msgget(key,IPC_CREAT|0777);

  (3)读写队列

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

    参数:int msqid ---队列id类似与文件描述符

                 const void *msgp发送消息内容(数据+标号)

                 size_t msgsz消息数据大小

                 int msgflg 标志一般设置0;

    要发送的内容

struct msgbuf {
         long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
          };

    一般写成msgsnd(msgid,&msgbuffer,sizeof(msgbuffer),0);

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

    参数:int msqid ---队列id类似与文件描述符

                 void *msgp保存读取的消息内容(数据+标号)

                 size_t msgsz 为msgp空间大小

       long msgtyp 数据标志---message type

                  int msgflg 标志一般设置0;

                  一般写成msgrcv(msgid,&msgbuffer,sizeof(msgbuffer),100,0);

    如果队列中没有数据就会阻塞。

  (4)销毁队列

 

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

 

    参数:int msqid 队列id号

            int cmd 控制命令

            struct msqid_ds *buf--有第二参数决定

            删除队列:把第二个参数cmd设置为IPC_RMID,把第三个参数设置NULL

               一般写成 int msgdestroy = msgctl(msgid,IPC_RMID,NULL);

magsend.c

#include <stdio.h>
#include <sys/types.h>
#incldude <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    //获取键值
    key_t key=ftok("/tmp",100);
    printf("key=%d
",key);

    //通过key获取消息队列
    int msgid=msgget(key,IPC_CREATE|0777);
    if(msgid<0){
        perror("创建消息队列失败
");
        return -1;
    }

    struct msgbuf{
        long mtype;
        char mtext[128];
    }msgbuffer;
    int i=0;
    while(1){
        msgbuffer.mtype=100;
        sprintf(msgbuffer.mtext,"send data %d",i++);
        //往队列中发送数据
        msgsend(msgid,&msgbuffer,sizeof(msgbuffer),0);
        sleep(1);
    }

    //销毁队列
    int msgdestroy=msgctl(key,IPC_RMID,NULL);
    return 0;
}

2.共享内存

  ipcs -m查询

  ipcrm -m id号 删除

头文件

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

  (1)获取key值

int shmget(key_t key, size_t size, int shmflg);

  参数:key_t key--键值

        size_t size--申请共享内存大小 int size = 1920*1080*4;

       int shmflg --权限,创建标准IPC_CREAT

  返回:共享内存id, 失败-1

  一般写成 int shmid = shmget(key,size,IPC_CREAT|0777)

  (2)把内核共享空间映射到用户空间

void *shmat(int shmid, const void *shmaddr, int shmflg);

  参数:int shmid共享内存id号

         const void *shmaddr,如果为NULL系统自定分配一块用户空间与内核空间映射并且返回首地址,

         int shmflg --权限标准 如果第二个参数设置NULL,此参数可以设置0

  返回值:成功返回映射到用户空间的首地址, 失败(void *) -1

  一般写成 usigned int *mp = shmat(shmid,NULL,0);

  (3)释放映射空间 

int shmdt(const void *shmaddr);

  一般写成 shmdt(mp);

  (4)释放共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  参数:shmid--共享内存id

        cmd是命令 IPC_RMID

          buf如果是删除这里直接设置NULL

  一般写成  shmctl(shmid, IPC_RMID, NULL);

shmwrite.c

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

int main()
{
    //获取key值
    key_t key=ftok("/tmp",100);
    //根据key获取共享内存
    int size=1024*640*4;
    int shmid=shmget(key,size,IPC_CREAT|0777);
    //映射空间
    unsigned int *mp=shmat(shmid,NULL,0);

    while(1){
        //改变共享内存mp
        unsigned int coloe;
        scanf("%u",&color);
        for(int i=0;i<size/4;i++){
            mp[i]=color;
        }
    }

    //释放映射
    shmdt(mp);
    //删除共享内存
    shmctl(shmid,IPC_RMID,NULL);
}
shmshow.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#incllude <sys/mman.h>

int main()
{
    //获取key
    key_t key=ftok("/tmp",100);
    int size=1024*640*4;
    int shmid=shmget(key,size,IPC_CREAT|0777);
    //映射空间
    unisgned int *mp=shmat(shmid,NULL,0);

    //打开lcd
    int fd=open("/dev/fb0",O_RDWR);
    if(fd<0){
        perror("open lcd fail");
    }
    unisgned int *lcdmp=mmap(NULL,size,PORT_READ|PORT_WRITE,MAP_SHARED,fd,0);

    for(int i=0;i<size;i++){
        lcdmp[i]=0xff0000;
    }

    while(1){
        memcpy(lcdmp,mp,size);
        usleep(1000);
    }

    //释放映射
    shmdt(mp);

    //删除共享内存
    shmctl(shmid,IPC_RMID,NULL);
}

3.信号量

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

  (1)获取键值key

key_t ftok(const char *pathname, int proj_id);

  一般用法key_t key = ftok("/tmp", 100);

  (2)通过key值获取信号量

int semget(key_t key, int nsems, int semflg);

    参数:key_t key键值

            int nsems申请信号量个数

          int semflg 创建标志,权限

    返回值:成功返回信号量id,失败-1

    int semid = semget(key, 2, IPC_CREAT|0777);

   (3)初始化信号量

int semctl(int semid, int semnum, int cmd, ...);

    参数:int semid信号量id

            int semnum 要设置的信号量编号(编号从0开始)

         第三个参数和第四个采参数相关联

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

      比方说第三个参数是SETVAL,那么第四个参数就是联合体中的val成员

union semun
    {
        int val;
    } sval;

    int val = 1;
    sval.val = 1;
    int ret = semctl(semid, 0, SETVAL, val);

  (4)pv操作,获取和释放资源

int semop(int semid, struct sembuf *sops, size_t nsops);

    参数:int semid信号量编号

            struct sembuf *sops--pv操作结构体

         size_t nsops--指定第二个参数指针所指向的对象有多少个连续对象

     PV操作之前先要初始化,定义一个结构体

struct sembuf
{
unsigned short  sem_num;  /* semaphore number */
    short   sem_op;   /* semaphore operation */  如果是p操作sem_op 为-1.如果是v操作sem_op值加1
    short   sem_flg;  /* operation flags */
};

    p操作  sem_p(semid, 0);

    v操作  sem_v(semid, 1);

  (5)释放信号量

int semctl(int semid, int semnum, int cmd, ...);

    常用  semctl(semid, 0, IPC_RMID, NULL);

senA.c

void sem_p(int semid, int num)//p操作
{    
    struct sembuf sbuf;
    sbuf.sem_num = num;
    sbuf.sem_op = -1;
    sbuf.sem_flg = 0;
    semop(semid, &sbuf, 1);
}

void sem_v(int semid, int num)//v操作
{    
    struct sembuf sbuf;
    sbuf.sem_num = num;
    sbuf.sem_op = 1;
    sbuf.sem_flg = 0;
    semop(semid, &sbuf, 1);
}

int main(void)
{
    //1.获取key
    key_t key = ftok("/tmp", 100);
    //2.获取信号量
    int semid = semget(key, 2, IPC_CREAT|0777);
    //3.初始化信号--编号为0的信号量
    union semun
    {
        int val;
    } sval;

    int val = 1;
    sval.val = 1;
    int ret = semctl(semid, 0, SETVAL, val);

    while(1)
    {
        //4.p操作
        sem_p(semid, 0);
            
        printf("A进程----操作
");
        sleep(1);
    
        //5.v操作
        sem_v(semid, 1);
    }

    //释放信号量
    semctl(semid, 0, IPC_RMID, NULL);
}
semB.c
void sem_p(int semid, int num)
{    
    struct sembuf sbuf;
    sbuf.sem_num = num;
    sbuf.sem_op = -1;
    sbuf.sem_flg = 0;
    semop(semid, &sbuf, 1);
}

void sem_v(int semid, int num)
{    
    struct sembuf sbuf;
    sbuf.sem_num = num;
    sbuf.sem_op = 1;
    sbuf.sem_flg = 0;
    semop(semid, &sbuf, 1);
}

int main(void)
{
    //1.获取key
    key_t key = ftok("/tmp", 100);
    //2.获取信号量
    int semid = semget(key, 2, IPC_CREAT|0777);
    //3.初始化信号--编号为0的信号量
    #if 0
    union semun
    {
        int val;
    } sval;

    int val = 0;
    sval.val = 0;
    int ret = semctl(semid, 1, SETVAL, val);
    #endif 

    while(1)
    {
        //4.p操作
        sem_p(semid, 1);
            
        printf("B进程----操作
");
        //sleep(1);
    
        //5.v操作
        sem_v(semid, 0);
    }

    //释放信号量
}

PS:哪里写错了请指正,互相学习。

原文地址:https://www.cnblogs.com/smallqizhang/p/12455466.html