Linux--进程间通讯IPC(信号量,消息队列,共享内存)

信号量

1、 临界资源
同一时刻, 只能被一个进程访问的资源。
2、 临界区
访问临界资源代码区域
3、 原子操作
任何情况下都不能被打断的操作
4、 内核对象
用于对进程间通讯时, 多进程能够访问同一资源的记录。
信号量的作用: 进程间同步控制
信号量相当于记录资源能同时被多少个进程访问。
信号量的操作:
创建或获取: 如果是创建, 必须初始化。 如果获取, 则不能初始化。
减一操作:
P 操作
加一操作:
V 操作
删除:
int semget((key_t)key, int nsems, int flag); // 创建或者获取
int semop(int semid, struct sembuf *buf, int lenth); // P V 操作
// 初始化和删除
int semctl(int semid, int pos, int cmd, /*union semun un*/);
sem_get(); // 获取信号量, 如果是第一次, 则创建信号量并初始化。
sem_P(); // 执行 P 操作
sem_V(); // 执行 V 操作
sem_del(); // 删除信号量

sem头文件和代码如下

#ifndef __SEM_H
#define __SEM_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semid;

union semun
{
	int val;
};

void sem_get(); //创建或者获取信号量
void sem_p();  //P操作
void sem_v();  //V操作
void sem_del(); //删除



#endif
#include "sem.h"

void sem_get()
{
	semid = semget((key_t)1234, 1, 0664);
	if(semid == -1) // 获取失败, 内核中并没有这个信号量集
	{
		semid = semget((key_t)1234, 1, 0664 | IPC_CREAT);
		assert(semid != -1);

		//本次获取是创建信号量集,所以必须初始化

		union semun v;
		v.val = 0;
		if(-1 == semctl(semid, 0, SETVAL, v))
		{
			perror("error");
			exit(0);
		}
	}
}
void sem_p()
{
	struct sembuf buff;
	buff.sem_num = 0;
	buff.sem_op = -1;
	buff.sem_flg = SEM_UNDO;

	if(-1 == semop(semid, &buff, 1))
	{
		perror("p error");
		exit(0);
	}
}
void sem_v()
{
	struct sembuf buff;
	buff.sem_num = 0;
	buff.sem_op = 1;
	buff.sem_flg = SEM_UNDO;

	if(-1 == semop(semid, &buff, 1))
	{
		perror("p error");
		exit(0);
	}
}
void sem_del()
{
	if(-1 == semctl(semid, 0, IPC_RMID))
	{
		perror("del error");
		exit(0);
	}
}


根据sem代码练习 输入“start”执行输出100以内素数  代码如下

输入start开始

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<ctype.h>
#include<assert.h>
#include<string.h>
#include"sem.c"
#include"sem.h"

int  main()
{
	sem_get();

	while(1)
	{
		printf("input:\n");
		fflush(stdout);
		char buff[128]={0};
		fgets(buff,127,stdin);
		if(strncmp(buff,"start",5)==0)
		{
			sem_v();
            //printf("start\n");	
     	}
	
	}
}

执行素数

#include<stdio.h>
#include<unistd.h>
#include"sem.c"
#include"sem.h"

int fun(int n)
{
	int flag;
	int i;
	int j;
	for( i=2;i<n;i++)
	{
		flag = 1;
		for(j=2;j<i-1;j++)
		{
           if(i%j==0)
		   {
			   flag=0;
		   }
		}
		if(flag==1)
		{
			printf("%d\n",i);
		}
	}
}
int main()
{
	sem_get();
	sem_p();
	int i=100;
        fun(i);
        return 0;
}

如图

消息队列

ipcs -s 查看系统上所有的信号量集
ipcrm -s semid 删除系统上的信号量集
ipcs -q 查看系统上所有的消息队列
ipcrm -q msgid 删除系统上的消息队列
ipcs -m 查看系统上所有的共享内存
ipcrm -m shmid 删除系统上的共享内存
A 进程负责循环获取用户输入, 当用户输入“OK” 后, 通知 B 进程打印 100 以内所有的素数。
消息队列
消息: 数据
& 类型
队列: 数据结构, 先进先出
消息队列: 是一种临时存储消息的队列, 完成进程间数据传递, 优先级队列

特点:
与信号量对比: 都以内核对象来确保多进程访问同一个消息队列, 信号量进行进程同步控制, 消息队列发送实际数据。
与管道对比: 管道发送的数据没有类型, 读取数据端无差别从管道中按照数据的前后顺序读取数据, 消息队列数据有类型, 读端可以根据数据类型读取特定数据。
消息队列操作:
创建或获取:
int msgget((key_t)key, int flag);
flag:
权限 以及控制
IPC_CREAT: 如果存在, 直接获取
如果不存在, 则创建
发送消息:
int msgsnd(int msgid, void *ptr, size_t size, int flag);
ptr: ptr
指向一个结构体: 类型 + 数据
size: 数据的大小
获取消息:
int msgrcv(int msgid, void *ptr, size_t size, long type, int flag);
删除消息队列:
int msgctl(int msgid, int cmd, struct msgid_ds * buff);


代码如下

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

struct msgbuff
{
	long type;
	char  data[128];
};

void main()
{
	int msgid = msgget((key_t)1234, IPC_CREAT | 0664);
	assert(msgid != -1);


	struct msgbuff  buff;
	buff.type = 1000;
	strcpy(buff.data, "hello");

	msgsnd(msgid, &buff, strlen(buff.data), 0);

	buff.type = 2000;
	strcpy(buff.data, "world");

	msgsnd(msgid, &buff, strlen(buff.data), 0);
}

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

struct msgbuff
{
	long type;
	char  data[128];
};

void main()
{
	int msgid = msgget((key_t)1234, IPC_CREAT | 0664);
	assert(msgid != -1);


	struct msgbuff buff;
	memset(&buff, 0, sizeof(buff));

	msgrcv(msgid, &buff, 127, 1000, 0);

	printf("%s\n", buff.data);
  
  
}

共享内存

共享内存也有内核对象来管理共享的内存区域

特点: 共享内存是最快的一种 IPC, 在各个进程都有指针直接指向开辟内存区域。 访问时
当做本进程中的一个内存控制直接操作。
操作:
创建或者获取
int shmget((key_t)key, size_t size, int flag);
size:
开辟内存空间的大小,
flagIPC_CREAT 如果存在, 则获取
如果不存在, 则创建
链接:
void * shmat(int shmid, void *addr, int flag);
返回值一个指向共享内存首地址的指针
断开链接:
int shmdt(void *ptr);
此函数只完成断开链接操作, 并不会删除共享内存。
删除内核对象:
int shmctl(int shmid, int cmd , struct shmid_ds *buff);
注意:
共享内存是两个以上的进程能够操作同一块物理空间的内存区域,所以共享的区域
就成了临界资源, 所以对于共享区域的访问必须做同步控制。(信号量)




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值