8.6IO进程线程

笔记

进程

3.6IPC通信机制

        1> system V提供了三种IPC(interprocess communication)进程间通信方式

        消息队列:本质上在内核空间维护了一个队列,发送者可以将消息先放入到该队列上,接收者根据自己的需求读取队列上的信息

        共享内存:本质上在独立于多个进程外,分配一个物理内存的映射,使得多个进程可以共享该内存空间

        信号量集:将多个无名信号量,放入一个集合中,分别控制不同的进程,用于进程间同步问题

        2> 该通信机制是独立于进程而存在的:当进程将数据写入该通信对象中后,即使进程已经结束,对象中保存的内容仍然存在

        3> IPC对象相关指令

1、ipcs :查看当前所有的ipc对象的信息

2、ipcs -q:查看消息队列的信息

3、ipcs -m:查看共享内存的信息

4、ipcs -s:查看信号量集的信息

5、ipcrm -q\-m\-s ID号:删除指定的ipc对象

3.7 消息队列

        1> 消息队列的特点

        放入消息队列中的消息需要进行封装,包括消息类型和消息数据

        消息队列的消息遵循先进先出原则,如果取出时不指定类型,则默认取第一个,如果指定了类型,则取第一个放入队列中的该消息

        消息队列独立于进程而存在,当一个进程将消息放入队列后,及时进程退出了,也不会删除消息队列中的该消息

        消息队列的大小为16KB

        2> 消息队列的相关API函数接口

1、创建用于生成消息队列的钥匙
       #include <sys/types.h>
       #include <sys/ipc.h>

       key_t ftok(const char *pathname, int proj_id);
        功能:通过给定的文件路径和一个随机ID值创建出一个用于IPC通信的key值       ftok("/", 'k');
        参数1:文件路径,该文件的inode号占key值的2字节,该文件的设备号占key值的1字节
        参数2:一个给定的随机值,该值占key值的1字节
        返回值:成功返回创建出的key值,失败返回-1并置位错误码

2、通过钥匙创建出一个消息队列对象
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgget(key_t key, int msgflg);
        功能:通过给定的key值创建一个消息队列
        参数1:用于创建消息队列的key值,该值可以由ftok创建出来,也可以是 IPC_PRIVATE,表示进行亲缘进程间的通信
        参数2:创建标识位
                IPC_CREAT:表示本次操作要创建一个消息队列,如果该key值对应的消息队列已经存在,则直接打开该消息对象
                IPC_EXCL:表示本次确保要创建一个新的消息队列,如果该消息队列已经存在,则该函数报错,错误码为EEXIST
                创建文件的权限,也在该参数中,使用位或连接
        返回值:成功返回消息队列的id号,失败返回-1并置位错误码

3、向消息队列中存放消息
       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
       功能:向消息队列中存放消息,要求当前进程对消息队列具有可写权限
       参数1:消息队列的id号
       参数2:是指向封装好的消息的起始地址,通常类型如下,但是需要用户自己定义
          struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };
        参数3:表示参数2中,消息正文的大小,不包含消息类型的大小
        参数4:发送标识位,表示是否阻塞
            0:表示阻塞
            IPC_NOWAIT:表示非阻塞
        返回值:成功返回0,失败返回-1并置位错误码

4、从消息队列中取消息
        ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
 int msgflg);
        功能:从消息队列中取消息
        参数1:消息队列的id号
        参数2:存放消息的容器起始地址
        参数3:消息正文的大小
        参数4:取出消息的类型
                >0: 表示取出该类型的消息的第一个消息
                =0:不限制类型,直接取消息队列中的第一个
                <0: 取出消息队列中类型小于msgtyp绝对值的第一个
                    例如:  50   10   2   10    6   6  8
                    -7:    2  6  6
    ---> 2
        参数5:是否阻塞
            0:表示阻塞
            IPC_NOWAIT:表示非阻塞
        返回值:成功返回成功读取的字节个数,失败返回-1并置位错误码

5、控制消息队列
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgctl(int msqid, int cmd, struct msqid_ds *buf);
       功能:完成对消息队列指定的cmd操作
       参数1:消息队列的id号
       参数2:操作指令
          IPC_STAT:获取消息队列的属性,此时参数3必须要给定,表示接收消息队列的属性
             struct msqid_ds {
               struct ipc_perm msg_perm;     /* 拥有者和权限 */
               time_t          msg_stime;    /* 最新一次向消息队列中发送数据的时间 */
               time_t          msg_rtime;    /* 最新一次消息队列接受数据的时间 */
               time_t          msg_ctime;    /* 最新一次操作消息队列的时间 */
               unsigned long   __msg_cbytes; /* 当前队列中已用的字节数 */
               msgqnum_t       msg_qnum;     /* 当前队列中消息的个数*/
               msglen_t        msg_qbytes;   /* 队列的最大容量,默认是16K */
               pid_t           msg_lspid;    /* 最后一次向消息队列中发送消息的进程id号 */
               pid_t           msg_lrpid;    /* 最后一次从消息队列中取消息的进程id号 */
           };
               对第一个成员的介绍
              struct ipc_perm {
               key_t          __key;       /* 键值 */
               uid_t          uid;         /* 当前拥有者的用户id号 */
               gid_t          gid;         /*当前拥有者的组id号 */
               uid_t          cuid;        /* 创建消息队列的进程的用户id */
               gid_t          cgid;        /* 创建消息队列进程的组id号 */
               unsigned short mode;        /* 操作权限 */
               unsigned short __seq;       /* 队列号 */
           };
         IPC_SET:设置消息队列的属性  
         IPC_RMID:删除消息队列,当参数2位该值时,参数3可以忽略,直接填NULL即可
         返回值:成功返回0,失败返回-1并置位错误码
3.8 共享内存

        1> 共享内存的特点

1、共享内存表示的是多个进程共享一个外部的物理内存,效率比较高

2、共享内存具有时效性,存放到共享内存区域中的数据,如果不及时读取,下一次写入后,前面的数据会被覆盖

3、共享内存的操作不是一次性的,写入到共享内存中的数据,即使读取出去后,依然存在于共享内存,直到下一次被覆盖

        2> 共享内存的PAI函数接口

1、创建共享内存对象
         #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, size_t size, int shmflg);
       功能:通过给定的key值创建一个共享内存的对象,并返回该对象的id
       参数1:key值,可以是IPC_PRIVATE也可以是由ftok创建出来的
       参数2:申请的共享内存段的大小,必须是PAGE_SIZE的整数倍,如果超过,则向上取整
       参数3:创建的标识
                IPC_CREAT:表示本次操作要创建一个共享内存,如果该key值对应的共享内存已经存在,则直接打开该共享内存对象
                IPC_EXCL:表示本次确保要创建一个新的共享内存,如果该共享内存已经存在,则该函数报错,错误码为EEXIST
                创建文件的权限,也在该参数中,使用位或连接
        返回值:成功返回创建出来的共享内存的id,失败返回-1并置位错误码
 
2、将共享内存地址映射到用户空间
       void *shmat(int shmid, const void *shmaddr, int shmflg);
       功能:映射共享内存的地址到用户空间
       参数1:共享内存ID
       参数2:对齐页地址,一般填NULL,让系统选择合适的对齐页
       参数3:共享内存的权限
           SHM_RDONLY:只读权限
           0:    读写权限
       返回值:  成功返回映射的共享内存段的地址,失败返回(void *)-1并置位错误码          
       
 3、取消共享内存的映射
             int shmdt(const void *shmaddr);
             功能:取消共享内存的映射
             参数:共享内存映射的地址
             返回值:成功返回0,失败返回-1并置位错误码
                 
 4、共享内存的控制函数
        #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmctl(int shmid, int cmd, struct shmid_ds *buf);
       功能:控制共享内存对象
       参数1:共享内存的id号
       参数2:操作指令
          IPC_STAT:获取消息队列的属性,此时参数3必须要给定,表示接收消息队列的属性
         IPC_SET:设置消息队列的属性  
         IPC_RMID:删除消息队列,当参数2位该值时,参数3可以忽略,直接填NULL即可
        返回值: 成功返回0,失败返回-1并置位错误码
                                      
      
        

作业

使用消息队列完成两个进程之间相互通信

#include <myhead.h>
struct msgbuf
{
	long mtype;    //类型
	char mtext[1024];//存放消息
};
#define SIZE sizeof(struct msgbuf)-sizeof(long)
void task()
{
	char flag=0;
	int fp=-1;
	if((fp=open("./user2.txt",O_RDONLY))==-1)
	{
		perror("pen fp error");
		return ;
	}
		system("clear");
		while(read(fp,&flag,sizeof(flag))!=0)
		{
			printf("%c",flag);
		}
		putchar(10);
		printf("请输入:\n");
		close(fp);
}
int main(int argc, const char *argv[])
{
	//创建key值,用于创建消息队列
	key_t key=ftok("/",'k');
	if(key==-1)
	{
		perror("ftok,error");
		return-1;
	}
	//通过key创建消息队列
	int msgid =msgget(key,IPC_CREAT|0664);
	if(msgid==-1)
	{
		perror("msgget error");
		return -1;
	}
	pid_t pid=fork();
	if(pid>0)
	{
		FILE *fp=NULL;
		if((fp=fopen("./user2.txt","a"))==NULL)
		{
			perror("open user2.txt error");
			return -1;
		}
		struct msgbuf buf;
		printf("请输入\n");
		while(1)
		{
			buf.mtype=1;
			fgets(buf.mtext,SIZE,stdin);
			buf.mtext[strlen(buf.mtext)-1]=0;
			msgsnd(msgid,&buf,SIZE,0);
			if(strcmp(buf.mtext,"quit")==0)
				break;
			fprintf(fp,"我:%s\n",buf.mtext);
			fflush(fp);
			task();
			
		}
		fclose(fp);
		exit(EXIT_SUCCESS);
	}else if(pid==0)
	{
		FILE *fp=NULL;
		if((fp=fopen("./user2.txt","a"))==NULL)
		{
			perror("open user2.txt error");
			return -1;
		}
		struct msgbuf buf;
		while(1)
		{
			msgrcv(msgid,&buf,SIZE,2,0);
			if(strcmp(buf.mtext,"quit")==0)
				break;
			fprintf(fp,"\t\t\t\t%s:user2\n",buf.mtext);
			fflush(fp);
			task();
		}
		fclose(fp);
		exit(EXIT_SUCCESS);
	}
	wait(NULL);
	wait(NULL);
	return 0;
}
#include <myhead.h>
struct msgbuf
{
	long mtype;    //类型
	char mtext[1024];//存放消息
};
#define SIZE sizeof(struct msgbuf)-sizeof(long)
void task()
{
	char flag=0;
	int fp=-1;
	if((fp=open("./user1.txt",O_RDONLY))==-1)
	{
		perror("pen fp error");
		return ;
	}
		system("clear");
		while(read(fp,&flag,sizeof(flag))!=0)
		{
			printf("%c",flag);
		}
		putchar(10);
		printf("请输入:\n");
		close(fp);
}
int main(int argc, const char *argv[])
{
	//创建key值,用于创建消息队列
	key_t key=ftok("/",'k');
	if(key==-1)
	{
		perror("ftok,error");
		return-1;
	}
	//通过key创建消息队列
	int msgid =msgget(key,IPC_CREAT|0664);
	if(msgid==-1)
	{
		perror("msgget error");
		return -1;
	}
	pid_t pid=fork();
	if(pid>0)
	{
		FILE *fp=NULL;
		if((fp=fopen("./user1.txt","a"))==NULL)
		{
			perror("open user1.txt error");
			return -1;
		}
		struct msgbuf buf;
		printf("请输入:\n");
		while(1)
		{
			buf.mtype=2;
			fgets(buf.mtext,SIZE,stdin);
			buf.mtext[strlen(buf.mtext)-1]=0;
			msgsnd(msgid,&buf,SIZE,0);
			if(strcmp(buf.mtext,"quit")==0)
				break;
			fprintf(fp,"我:%s\n",buf.mtext);
			fflush(fp);
			task();
			
		}
		fclose(fp);
		exit(EXIT_SUCCESS);
	}else if(pid==0)
	{
		FILE *fp=NULL;
		if((fp=fopen("./user1.txt","a"))==NULL)
		{
			perror("open user1.txt error");
			return -1;
		}
		struct msgbuf buf;
		while(1)
		{
			msgrcv(msgid,&buf,SIZE,1,0);
			if(strcmp(buf.mtext,"quit")==0)
				break;
			fprintf(fp,"\t\t\t\t%s:user1\n",buf.mtext);
			fflush(fp);
			task();
		}
		fclose(fp);
		exit(EXIT_SUCCESS);
	}
	wait(NULL);
	wait(NULL);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值