IPC通信:

共享内存,信号量集,消息队列

查看所有的IPC

指令:ipcs

shm共享内存    ipcs  -m

sem信号量集     ipcs  -s

msg消息队列     ipcs  -q

删除:

ipcrm  -m  标识符     删共享内存

ipcrm  -s   标识符     删信号量集

ipcrm  -q   标识符     删消息队列


键值:ftok

键值含义:用于标识共享内存、消息队列以及信号量集

保证多个进程打开的共享内存、消息队列、信号量集是同一个

# include <sys/types.h>

# include <sys/ipc.h>

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

参数:pathname就是你指定的文件名(该文件必须是存在而且可以访问的)

proj_id:0-255的任意一个数

返回值:当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回

int key = ftok(“/home/fuc/2_208”,1);

共享内存

1.创建共享内存 

2.将共享内存映射到自己的进程空间,得到首地址

3.操作地址对应的空间 

4.不想用了,解除映射

5.彻底不用了,删除


1》创建/获取共享内存 -- shmget:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

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

参数

        key:键值  ftok的返回值;

        size:大小

        shmflg:IPC_CREAT|0664

如果共享内存不存在,创建并打开,存在,只打开

    返回值:成功返回内存段标识符,失败-1


2》映射:把共享内存区域映射到调用进程的地址空间中去

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

参数

        shmid:要映射的共享内存区标识符

        shmaddr:NULL

        shmflg:默认 0:共享内存可读写

返回值:

成功:被映射的段地址void * -- 万能指针

失败返回NULL


3》解除映射

int shmdt(const void *shmaddr);

    参数:    被映射的共享内存段地址,shmat的返回值

    返回值:成功返回0失败返回-1


4》删除/修改共享内存

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

参数:    shmid:    shmget的返回值

        cmd:        选择的操作

         IPC_STAT:获取共享内存属性,传入空的buf

         IPC_SET:修改共享内存的属性,传入设置号的buf

         IPC_RMID:删除共享内存,此时第三个参数为NULL

    buf:根据第二个参数决定


插入:

内存复制:memcpy

void *memcpy(void *destin, void *source, unsigned n);

参数

destin:指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。

source:指向要复制的数据源,类型强制转换为 void* 指针。

n-- 要被复制的字节数。

返回值

该函数返回一个指向目标存储区destin的指针。

功能

从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。

memcpy() 并不关心被复制的数据类型,只是逐字节地进行复制

信号量集

1》创建信号量集合:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

semget:创建一个信号量集或访问一个已存在的信号量集

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

参数:key:键值使用ftok从文件路径名中产生

 nsems:通常取值为1,表示创建1组信号量;

semflg:IPC_CREA|0666表示若信号量集合已存在,返回该信号量集合的标识符,不存在,创建并返回信号量集合的标识符      

   返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1


2》信号量的初始化  semctl  - 控制信号量信息

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

    参数

    semid:是由 semget 返回的信号量标识符。

    semnum:你要初始化的信号量的编号(从0开始)

    cmd 命令:

删除 IPC_RMID(立即删除信号集,唤醒所有被阻塞的进程)

获取 GETVAL(根据 semnum指定的编号返回相应信号的值, 此时该函数返回值就是你要获得的信号量的值,不再是 0或-1)             

设置 SETVAL(根据 semunm 指定的编号设定相应信号的值(用联合体中val成员的值设置信号量集合中单个信号量的值))

       如果有第四个参数类型如下

  union semun {

 short val;          /*SETVAL用的值*/

struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构(则是一个内核结构体)*/

 unsigned short* array; /*SETALL、GETALL用的数组值*/

struct seminfo *buf;   /*为控制IPC_INFO提供的缓存(表示信号量系统资源配置信息)*/


    返回值:成功:返回相应的值,失败:返回-1


3》信号量的还原和消耗semop

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

形参:

semid:semget返回值,就是信号量集和的标识符

sops:对信号量的操作,封装了一个结构体里面有

struct sembuf{

   unsigned short sem_num;  //信号在信号集中的索引,0代表第一个信号,1代表第二个信号

   short  sem_op;  //操作类型  +1,-1

   sem_op > 0  信号加上 sem_op 的值                                                                          sem_op < 0  信号减去 sem_op 的值。

 short  sem_flg;  //操作标志0,设置信号量的默认操作

}

 nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作

返回值:成功时,返回 0;失败时,返回-1

举例:

struct sem P = {0,-1,0};

struct sem V = {0,+1,0};

消耗:semop(semid, &P,1);//阻塞

还原:semop(semid, &V,1);

例题:通过两个进程,利用共享内存与信号量集输出helloworld++++++++++

首先创建1.c  2.c 分别用于利用共享内存与信号量集将信息存放到映射出来的内存中,3.c用来读取打印,seminit.c用来初始化

代码如下

1.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
int main()
{
    int key = ftok("/home/fuc",66);
    //创建共享内存:
    int shmid = shmget(key,2000,IPC_CREAT|0644);
    if(shmid == -1)
    {
        perror("shmget");
        return -1;
    }
    //映射
    char *p = (char *)shmat(shmid,NULL,0);
    if( p == NULL )
    {
        perror("shmat");
        return -1;
    }
    
    //获取信号量集合
    int key1 = ftok("/home/fuc",666);
    int semid = semget(key1,1,IPC_CREAT|0666);
    if(semid == -1)
    {
        perror("semget");
        return -1;
    }

    struct sembuf P = {0,-1,0};
    struct sembuf V = {0,+1,0};

    //操作 p
    int count = 0;
    while(1)
    {
        //消耗
        semop(semid,&P,1);
        strcat(p,"hello");
        usleep(1000);
        strcat(p,"world");
        //还原
        semop(semid,&V,1);
        count++;
        if(count == 100)
        {
            break;
        }
    }
    
    //解除映射
    shmdt(p);
}

2.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
int main()
{
    int key = ftok("/home/fuc",66);
    //创建共享内存:
    int shmid = shmget(key,2000,IPC_CREAT|0644);
    if(shmid == -1)
    {
        perror("shmget");
        return -1;
    }
    //映射
    char *p = (char *)shmat(shmid,NULL,0);
    if( p == NULL )
    {
        perror("shmat");
        return -1;
    }

    //获取信号量集合
    int key1 = ftok("/home/fuc",666);
    int semid = semget(key1,1,IPC_CREAT|0666);
    if(semid == -1)
    {
        perror("semget");
        return -1;
    }

    struct sembuf P = {0,-1,0};
    struct sembuf V = {0,+1,0};

    //操作 p
    int count = 0;
    while(1)
    {
        //消耗
        semop(semid,&P,1); 
        strcat(p,"+++++");
        usleep(1000);
        strcat(p,"+++++");
        semop(semid,&V,1);
        //还原
        count++;
        if(count == 100)
        {
            break;
        }
    }
    
    //解除映射
    shmdt(p);
}

3.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
int main()
{
    int key = ftok("/home/fuc",66);
    //创建共享内存:
    int shmid = shmget(key,2000,IPC_CREAT|0644);
    if(shmid == -1)
    {
        perror("shmget");
        return -1;
    }
    //映射
    char *p = (char *)shmat(shmid,NULL,0);
    if( p == NULL )
    {
        perror("shmat");
        return -1;
    }
    //操作 p
    printf("%s\n",p);
    //解除映射
    shmdt(p);
}

seminit.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
union semun{
               int              val;    
               struct semid_ds *buf;    
               unsigned short  *array;  
               struct seminfo  *__buf;  
};

int main()
{
    int key = ftok("/home/fuc",11);
    int semid = semget(key,1,IPC_CREAT|0666);
    if(semid == -1)
    {
        perror("semget");
        return -1;
    }
    union semun set;
    set.val = 1;//表示二值信号量
    int res = semctl(semid,0,SETVAL,set);
    if(res == -1)
    {
        perror("semctl");
        return -1;
    }
    return 0;
}

首先初始化,然后再同时运行1.c 2.c  同时运行方法./1.c & ./2.c  最后运行3.c进行打印内容