一、进程的介绍
- 进程不会占用磁盘空间,但是系统会给进程分配cpu和内存。
- 每个进程对应一个虚拟地址空间。
- 进程是程序在执行过程中分配和管理资源的基本单位。
- 进程是独立的,对一个进程操作不会影响其他进程。
二、进程间通信的方式
- 管道
- 信号
- 内存映射
- 套接字
- 共享内存
- 消息队列
三、管道
- 匿名管道
- 介绍 匿名管道只能够进行没有血缘关系的进程间通信,必须要在创建子进程之前,创建匿名管道。
- 函数
- 测试代码
- 有名管道
- 介绍 会在磁盘上创建一个大小为0的管道文件,能够实现有血缘关系和无血缘关系进程间的通信。
- 函数
- 测试代码
- 共同点
- 默认都是是阻塞的,如果只打开了一端,则阻塞。
- 数据结构都是队列,数据先进先出,并且一个只能被读一次。
- 如果在通信过程中,写端被关闭,读端解除阻塞。
- 如果在通信过程中,读端关闭,则操作系统会给写端发送一个SIGPIPE信号,终止写端进程,这个行为称作管道破裂。
- 通信流程
- 有血缘关系 (1)父进程创建内存映射区。
- 无血缘关系 (1)创建一个大小非0的磁盘文件。
- 函数
- 测试代码
#include <unistd.h>
#include <fcntl.h>
int pipe(int pipefd[2]);
参数:
pipefd[2]传出参数,fd[0]代表管道的读端,fd[1]代表管道的写端
返回值:
0:成功
-1:调用失败
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//创建匿名管道
int pipe_fd[2];
if(pipe(pipe_fd)==-1)
{
//如果创建失败,打印错误信息并退出进程
perror("pipe");
_exit(0);
}
//创建子进程
pid_t pid=fork();
char buf[1024];
if(pid>0)
{
close(pipe_fd[1]);
while(1)
{
//父进程读
int ret=read(pipe_fd[0],buf,sizeof(buf));
switch(ret)
{
case -1:
perror("read");
wait(NULL);
_exit(0);
case 0:
printf("read over....\n");
close(pipe_fd[0]);
wait(NULL);
_exit(0);
default:
printf("parent read %d byte date : %s",ret,buf);
break;
}
}
}
if(0==pid)
{
close(pipe_fd[0]);
int num=0;
for(;num<10;num++)
{
//子进程写
sprintf(buf,"child write %d\n",num*17);
int len=strlen(buf)+1;
write(pipe_fd[1],buf,len);
printf("child send %d byte buf date: %s",len,buf);
sleep(1);
}
printf("end of write....\n");
close(pipe_fd[1]);
}
return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数:
pathname:传入参数,要创建的管道文件的路径及文件名
mode:创建的文件权限,需要与~umask做按位与操作
返回值:
0:成功
-1:失败
write.c
int main()
{
int ret=mkfifo("test",0664);
if(-1==ret)
perror("mkfifo");
int fd=open("test",O_WRONLY);
if(-1==fd)
perror("open");
char buf[64];
for(int i=0;i<10;++i)
{
sprintf(buf,"date : %d\n",i);
write(fd,buf,strlen(buf)+1);
sleep(1);
}
close(fd);
return 0;
}
read.c
int main()
{
int fd=open("test",O_RDONLY);
if(-1==fd)
perror("open");
char buf[64];
int ret=0;
while(1)
{
ret=read(fd,buf,sizeof(buf));
if(0==ret)
{
printf("写端已关闭。。。\n");
break;
}
printf("%s",buf);
}
close(fd);
return 0;
}
二、内存映射
内存映射是将磁盘文件映射到内存中,进程通过修改内存就能修改磁盘文件。通信过程中不阻塞。(2)父进程创建子进程,它们共享父进程创建出的内存映射区。
(2)进程1通过这个磁盘文件创建内存映射区。
(3)进程2通过这个磁盘文件创建内存映射区。
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数:
addr: 传出参数,指向创建的内存映射区首地址
length:要创建的内存映射区的大小
prot: 对内存映射区的操作权限
PROT_READ: 读权限, 这个权限必须要有
PROT_WRITE: 写权限
PROT_READ | PROT_WRITE: 读写权限
flags:
MAP_SHARED: 映射区数据会自动和磁盘文件进行同步, 进程间通信必须设置这个选项
MAP_PRIVATE: 不同步
fd: open得到的文件描述符,调用是的flags必须和mmap的flags权限相同
offset: 指针偏移量,需要为4k的整数倍
有血缘关系
int main()
{
int fd=open("test.txt",O_RDWR);
int size=lseek(fd,0,SEEK_END);
void* ptr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
pid_t pid=fork();
if(pid>0)
{
strcpy((char*)ptr,"hello");
wait(NULL);
}
if(pid==0)
{
char buf[32];
strcpy(buf,(char*)ptr);
printf("%s\n",buf);
}
return 0;
}
无血缘关系
进程1
int main()
{
int fd=open("test.txt",O_RDWR);
int size=lseek(fd,0,SEEK_END);
void *ptr=mmap(NULL,size,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
int i=0;
char buf[32];
sprintf(buf,"hello%d",i++);
strcpy((char*)ptr,buf);
sleep(1);
return 0;
}
进程2
int main()
{
int fd=open("test.txt",O_RDONLY);
int size=lseek(fd,0,SEEK_END);
void *ptr=mmap(NULL,size,PROT_READ,MAP_SHARED,fd,0);
char buf[32];
strcpy(buf,(char*)ptr);
printf("%s\n",buf);
return 0;
}