进程间通信方式:system V的IPC对象(共享内存(share memory) 消息队列(message queue) 信号灯集)

进程间通信方式

传统进程间通信方式:
					无名管道
					有名管道
					信号
	
system V的IPC对象:
					共享内存(share memory)
					消息队列(message queue)
					信号灯集
	
BSD: 套接字

ipcs

ipcs -m	:查询显示当前系统的共享内存
ipcs -q	:查询显示当前系统的消息队列
ipcs -s	:查询显示当前系统的信号灯集

ipcrm -m shmid:删除某个共享内存
ipcrm -q msgid:删除某个消息队列
ipcrm -s semid:删除某个信号灯集

IPC步骤:

	  key						    id
ftok ----> shm_get/msg_get/sem_get ----> shmmat/shmdt/shmctrl
										 msgctrl/msgsend/msgrecv
										 semctrl/semop

ftok函数

#include 
#include 

/**************************************************
*key_t ftok(const char *pathname, int proj_id);
*功能:得到一个key
*参数:
*	pathname: 文件路径名
*	proj_id:  子序号 INODE的低8位 1/2/3/4
*
*返回值:
*	成功返回 key
*	失败返回 -1
***************************************************/

【3】共享内存share memory

	是一种通信效率最高的进程间通信方式,
		
	进程间通信时直接访问内存,不需要进行数据的拷贝。

#include 
#include 
#include 

		
步骤:
	1. ftok
	2. shmget
	3. shmat
	4. 进程间通信 fork
	5. shmdt
	6. shmctl

shmget函数

/*********************************************************		
*int shmget(key_t key, size_t size, int shmflg);
*功能:创建/打开共享内存
*参数:
*	key: IPC_PRIVATE 或 ftok的返回值
*	size: 共享内存区大小
*	shmflg: IPC_CREAT | 0666
*			
*返回值:
*	成功返回: 共享内存段标识符 shmid
*	失败返回:  -1
*********************************************************/

shmat函数

/*********************************************************		
*void *shmat(int shmid, const void *shmaddr, int shmflg);
*功能:映射共享内存
*参数:
*	shmid: 共享内存段标识符
*	shmaddr: NULL  (系统自动完成映射)
*	shmflg: 
			0 读写
*			SHM_RDONLY 只读
*返回值:
*	成功返回: 映射后的地址
*	失败返回: -1
*********************************************************/

shmdt函数

/*********************************************************		
*int shmdt(const void *shmaddr);
*功能:解除共享内存的映射
*
*参数:
*	shmaddr:映射后的地址
*			
*返回值:
*	成功返回: 0
*	失败返回: -1
*********************************************************/

shmctl函数

/*********************************************************		
*int shmctl(int shmid, int cmd, struct shmid_ds *buf);
*功能:共享内存控制函数
*参数:
*	shmid: 共享内存段标识符
*	cmd:
			IPC_STAT:获取对象属性
			IPC_SET: 设置对象属性
			IPC_RMID:删除对象
*	buf:
			NULL (指定IPC_STAT/IPC_SET时用以保存/设置属性)
*			
*返回值:
*	成功返回: 0
*	失败返回: -1
*********************************************************/		

代码展示

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, const char *argv[])
{

    key_t key;
    // 获取key值
    key = ftok("/",1);
    if (key == -1)
    {
        perror("ftok");
        return -1;
    }
    printf("%#x\n",key);
    // 创建共享内存
    int shmid = shmget(key,1024,IPC_CREAT | 0666);
    if (shmid == -1)
    {
        perror("shmget");
        return -1;
    }
    printf("shmid = %d\n",shmid);
    system("ipcs -m");

    // 映射
    char *p = shmat(shmid,NULL,0);
    if (NULL == p)
    {
        perror("shmat");
        // 销毁共享内存
        goto xxx;
        return -1;
    }
    // fork
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        return -1;
    }
    else if (pid == 0)    // 子
    {
        while (1)
        {
            char buf[100] = {0};
            fgets(buf,sizeof(buf),stdin);

            strcpy(p,buf);
            if (strncmp(buf,"quit",4) == 0)
                break;
        }
    }
    else{
        waitpid(pid,NULL,WNOHANG);
        while (1)
        {
            // 捕获SIGCONT信号,继续运行
            printf("p = %s\n",p);
            sleep(1);
            if (strncmp(p,"quit",4) == 0)
                break;
        }
    }
    // 解除映射
    int ret = shmdt(p);
    if (ret == -1)
    {
        perror("shmdt");
        goto xxx;
    }
    // 删除剩余共享内存
    shmctl(shmid, IPC_RMID,NULL);
    if (ret == -1)
    {
        perror("shmdt");
        goto xxx;
    }



xxx:
    sleep(2); // 防止出错
    char buf[32] = {0};
    sprintf(buf,"ipcrm -m %d",shmid);
    system(buf);
    system("ipcs -m");
    

    return 0;
}

【4】消息队列

#include 
#include 
#include 

步骤:
	1. ftok
	2. msgget
	3. 进程间通信
	4. msgsnd
	5. magrcv
	6. msgctl

msgget函数

/*********************************************************		
*int msgget(key_t key, int msgflg);
*功能:创建一个消息队列
*
*参数:
*	key:ftok的返回值key
*	msgflg:IPC_CREAT | 0666
*	
*返回值:
*	成功返回: msgid
*	失败返回: -1
*********************************************************/

msgsnd函数

/*********************************************************		
*int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
*功能:发送消息:将消息添加到消息队列
*
*参数:
*	msqid:msgid
*	msgp: &msg
			struct msgbuf{
				long mtype; //消息类型
				char mtext[N]; //消息正文
			}
			struct msgbuf msg;
*	msgsz:发送消息正文的字节数:sizeof(msg) - sizeof(long)
*	msgflg:
			0 : 阻塞
			IPC_NOWAIT :非阻塞
*
*返回值:
*	成功返回: 0
*	失败返回: -1
*********************************************************/

msgrcv函数

/*********************************************************		
*ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtype, int msgflg);
*功能:接收消息:从消息队列中去取消息
*
*参数:
*	msqid:msgid
*	msgp:&msg
			struct msgbuf{
				long mtype; //消息类型
				char mtext[N]; //消息正文
			}
			struct msgbuf msg;
*	msgsz:接收消息的字节数:sizeof(msg) - sizeof(long)
*	msgtype:long mtype; //消息类型
*	msgflg:
			0 : 阻塞
			IPC_NOWAIT :非阻塞
*
*返回值:
*	成功返回:接收到的消息的长度
*	失败返回:-1
*********************************************************/

msgctl函数

/*********************************************************		
*int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*功能:消息队列控制函数
*
*参数:
*	msqid:msgid
*	cmd:
			IPC_STAT:获取对象属性
			IPC_SET: 设置对象属性
			IPC_RMID:删除对象		
*	buf:
*			NULL
*返回值:
*	成功返回
*	失败返回
*********************************************************/

代码展示

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct msgbuf{
    long type;      // 消息类型
    char buf[100];  // 消息正文
}msg_buf;

int main(int argc, const char *argv[])
{

    key_t key;
    // 获取key值
    key = ftok("/",'a');
    if (key == -1)
    {
        perror("ftok");
        return -1;
    }
    printf("%#x\n",key);
    // 创建消息队列
    int msgid = msgget(key,IPC_CREAT | 0666);
    if (msgid == -1)
    {
        perror("shmget");
        return -1;
    }
    printf("shmid = %d\n",msgid);
    system("ipcs -q");
    // fork
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        return -1;
    }
    else if (pid == 0)    // 子
    {
        while (1)
        {
            char buf[100]={0};
            fgets(buf,sizeof(buf),stdin);
            msg_buf msg;
            msg.type = 100;
            strcpy(msg.buf,buf);
            // 发送函数
            msgsnd(msgid,&msg,sizeof(msg) - sizeof(long),0);
            if (strncmp(buf,"quit",4) == 0)
            {
                // 删除消息队列
                int ret = msgctl(msgid, IPC_RMID,NULL);
                if (ret == -1)
                {
                    perror("megctl");
                    goto xxx;
                }
                break;
xxx:
                sleep(2); // 防止出错
                char buf[32] = {0};
                sprintf(buf,"ipcrm -q %d",msgid);
                system(buf);
                system("ipcs -q");
            }
        }
    }
    else{
        waitpid(pid,NULL,WNOHANG);
        while (1)
        {
            msg_buf msg;
            // 接受消息,从消息队列中去取消息
            msgrcv(msgid,&msg,sizeof(msg)-sizeof(long),100,0);   
            if (strncmp(msg.buf,"quit",4)==0)
                break;
            printf("%s",msg.buf);
        }
    }


    

    return 0;
}

【5】信号灯集

#include 
#include 
#include 

步骤:
	1. ftok
	2. shmget
	3. shmat
*	4. semget
*	5. semctl
	6. 进程间通信
*	7. semop
*	8. semctl
	5. shmdt
	6. shmctl

semget函数

/*********************************************************		
*int semget(key_t key, int nsems, int semflg);
*功能:创建一个信号灯集
*
*参数:
*	key:IPC_PRIVATE 或 ftok的返回值
*	nsems:信号灯集中信号灯的数目
*	semflg:IPC_CREAT | 0666
*
*返回值:
*	成功返回: semid
*	失败返回:  -1
*********************************************************/

semctl函数

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

/*********************************************************		
*int semctl(int semid, int semnum, int cmd, .../*union semunarg*\);
*功能:信号灯集的控制函数
*
*参数:
*	semid:semid
*	semnum:要修改的信号灯编号
*	cmd:
		GETVAL:获取信号灯的值
		SETVAL:设置信号灯的值
		IPC_RMID:删除信号灯集
*
	.../*union semun
*返回值:
*	成功返回: 0
*	失败返回: -1
*********************************************************/

semop函数

/*********************************************************		
*int semop(int semid, struct sembuf *opsptr, size_t nops);
*功能:对信号灯执行P(-1) V(+1)操作
*
*参数:
*	semid:semid
*	opsptr:
			struct sembuf{
				short sem_num; //信号灯的编号
				short sem_op; 
					// 0 等待,直到信号灯值变为0
					// 1  V操作
					// -1 P操作
				short sem_flg; 
					// 0  阻塞
					// IPC_NOWAIT 非阻塞
			}
*	nops:要操作的信号灯的个数
*
*返回值:
*	成功返回: 0
*	失败返回: -1
*********************************************************/

代码展示

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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


int main(int argc, const char *argv[])
{

    key_t key;
    // 获取key值
    key = ftok("/",1);
    if (key == -1)
    {
        perror("ftok");
        return -1;
    }
    printf("%#x\n",key);
    // 创建共享内存
    int shmid = shmget(key,1024,IPC_CREAT | 0666);
    if (shmid == -1)
    {
        perror("shmget");
        return -1;
    }
    printf("shmid = %d\n",shmid);
    system("ipcs -m");
    // 创建信号灯集
    int semid = semget(IPC_PRIVATE, 2,IPC_CREAT|0666);
    if (semid < 0)
    {
        perror("semget");
        return -1;
    }

    union semun sem0 = {0};
    union semun sem1 = {1};
    semctl(semid, 0, SETVAL,sem0);
    semctl(semid, 1, SETVAL,sem1);
    // 映射
    char *p = shmat(shmid,NULL,0);
    if (NULL == p)
    {
        perror("shmat");
        // 销毁共享内存
        goto xxx;
        return -1;
    }
    // fork
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork");
        return -1;
    }
    else if (pid == 0)    // 子
    {
        while (1)
        {
            // V  / p  操作    V(A)  P(B)
            struct sembuf sem;
            sem.sem_num = 1;
            sem.sem_op = -1;
            sem.sem_flg = 0;
            semop(semid,&sem,1);
            char buf[100] = {0};
            fgets(buf,sizeof(buf),stdin);

            strcpy(p,buf);
            if (strncmp(buf,"quit",4) == 0)
                break;
            sem.sem_num = 0;
            sem.sem_op =  1;
            sem.sem_flg = 0;

            semop(semid,&sem,1);
        }
    }
    else{
        // waitpid(pid,NULL,WNOHANG);
        while (1)
        {
            struct sembuf sem;
            sem.sem_num = 0;
            sem.sem_op = -1;
            sem.sem_flg = 0;

            semop(semid,&sem,1);
            // 捕获SIGCONT信号,继续运行
            printf("p = %s",p);
            if (strncmp(p,"quit",4) == 0)
            {
                wait(NULL);
                break;
            }
            sem.sem_num = 1;
            sem.sem_op = 1;
            sem.sem_flg = 0;
            semop(semid,&sem,1);



        }
    }
    // 解除映射
    int ret = shmdt(p);
    if (ret == -1)
    {
        perror("shmdt");
        goto xxx;
    }
    // 删除剩余共享内存
    shmctl(shmid, IPC_RMID,NULL);
    if (ret == -1)
    {
        perror("shmdt");
        goto xxx;
    }
    // 删除信号等集
    ret = semctl(semid,0|1,IPC_RMID);
    if (ret < 0)
    {
        perror("semctl");
        return -1;
    }


xxx:
    sleep(2); // 防止出错
    char buf[32] = {0};
    sprintf(buf,"ipcrm -m %d",shmid);
    system(buf);
    system("ipcs -m");
    

    return 0;
}

你可能感兴趣的:(C语言,linux,c语言,信号处理,多进程)