进程第二天————进程的通信方式

25 篇文章 0 订阅
2 篇文章 0 订阅

进程:
进程的概念特点
进程类型:

交互类型
批处理进程
守护进程

进程状态
运行态 :进程正在运行,或者准备运行(就绪态)
等待态
可中断
不可中断
停止态
死亡态

  Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will
       display to describe the state of a process:
       D    uninterruptible sleep (usually IO)
       R    running or runnable (on run queue)
       S    interruptible sleep (waiting for an event to complete)
       T    stopped, either by a job control signal or because it is being traced.
       W    paging (not valid since the 2.6.xx kernel)
       X    dead (should never be seen)
       Z    defunct ("zombie") process, terminated but not reaped by its parent.

       For BSD formats and when the stat keyword is used, additional characters may be displayed:
       <    high-priority (not nice to other users)
       N    low-priority (nice to other users)
       L    has pages locked into memory (for real-time and custom IO)
       s    is a session leader
       l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
       +    is in the foreground process group.
       R running or runnable (on run queue) 
进程正在CPU上运行,或者在排队等待CPU 
S interruptible sleep (waiting for an event to complete) 
进程处于可打断的睡眠状态,在等待某些事件来打断睡眠状态(如硬件中断、进程等待的资源可获得、获得接收到某些信号等) 
D uninterruptible sleep (usually IO) 
进程处于睡眠不可打断的睡眠状态,发送信号并不能改变睡眠状态,通常是在等待某些IO操作完成(如等待设备驱动完成设备扫描) 
T stopped by job control signal 
进程执行终止,进程在接收到SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU中任意一个时会进入该状态,在终端中使用Ctrl^Z会使得正在运行的进程进入后台(发送的信号是SIGTSTP) 
t stopped by debugger during the tracing 
进程因为调试暂停了,比如调试器用ptrace()进行调试,进程暂停时就会进入这种状态 
X dead (should never be seen) 
进程已经死亡 
Z defunct (“zombie”) process, terminated but not reaped by its parent 
僵尸进程,进程已经结束运行,但是该进程的父进程还没有为它调用wait4()或者waitpid()。在wait调用之前内核不会丢弃已经结束运行的进程的数据,因为父进程可能需要这些数据。(和这个相关的一个概念是孤儿进程,指的是父进程先结束,子进程还在运行,子进程就变成了孤儿进程,由pid为1的init进程收养,其ppid会变成1< high-priority (not nice to other users) 
高优先级进程(静态优先级相关的概念) 
N low-priority (nice to other users) 
低优先级进程(静态优先级相关的概念) 
L has pages locked into memory (for real-time and custom IO) 
进程要求内核讲自己的部分内存维持在内存中,不要cache out到磁盘中 
s is a session leader 
该进程是所在会话的leader进程 
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) 
该进程包含多个线程 
+ is in the foreground process group 
运行在前台的进程,就是你直接在终端中执行命令并在当前终端等待其完成的进程

进程的前后台切换
1.进程在后台运行 ./si &
2.jobs 查看后台进行 ----只能在同一终端下使用
3.fg 作业号
fg 1 将后台进程放在前台进行
创建子进程:
fork()
waitpid() -----设置为非阻塞等待
wait() -----阻塞等待
wait(&status)
WIFEXITED(status) 判断子进程是否正常结束
WEXITSTATUS(status) 获得子进程返回值
WIFSIGNALED(status) 判断子进程是否被信号结束
WTERMSIG(status) 判读结束子进程的信号类型
exec函数族
system函数
#include <stdlib.h>
参数1:Linux命令
int system(const char *command);
在这里插入图片描述

守护进程
1.守护进程的特点:
(1).守护进程是Linux三种类型之一
(2).通常在系统启动时运行.系统关闭的结束,
(3).始终运行在后台
(4).独立于任何终端(和终端无关)
(5).周期性的执行某种任何或者等待处理特定事件
2.进程的管理
Linux以会话(session),进程组的形式管理进程
每个进程属于一个进程组,子进程属于该进程组
会话又是一个或者多个进程组的集合,通常(shell进程)用户打开一个终端,系统就会创建一个会话,所有通过该终端运行的进程都属于这个会话
shell进程—shell进程是该会话的首进程,也称为该会话组的组长
终端 -----控制终端
一个会话最多打开一个控制终端,当控制终端关闭时,所有的进程也会被结束
3.守护进程的创建
1.创建子进程,父进程退出
子进程称为孤儿进程,被init进程收养
子进程运行在后台
子进程仍然属于该终端的会话组
if(fork()>0)
{
exit(0);
}
2.子进程创建新的会话,
子进程称为新会话组的组长,子进程不在属于原来的会话,脱离原来的终端
#include <unistd.h>
返回值:若小于0,创建失败
pid_t setsid(void);

if(setsid()<0){
exit(-1)
}
3.更改当前目录
#include <unistd.h>
int chdir(const char *path);
chdir(“/”) -----根目录
chdir(“/tmp”) ----777
两种目录权限不一样,守护进程会一直在后台运行,其工作目录不能为删除
4.重设文件权限掩码
文件权限掩码设置为0,只影响当前进程创建的文件
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
if(umask(0)<0)
{
exit(-1);
}
5.关闭从父进程继承的打开的文件描述符
#include <unistd.h>
int getdtablesize(void); -----获得打开进程的最大文件个数
----已脱离终端,stdin/stdout/stderr无法在使用
int i=0;
for(i=0;i<getdtablesize();i++)
{
close(i);
}
6.每个1秒将系统时间写入time.log

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
int main(int argc, const char *argv[])
{
	//创建子进程,父进程退出
	if(fork()>0)
	{
		exit(0);
	}
	//创建新的会话
	if(setsid()<0)
	{
		exit(-1);
	}
	//改变当前目录
	chdir("/tmp");
	//修改文件掩码
	if(umask(0)<0)
	{
		exit(-1);
	}
	//关闭继承下来的文件描述符
	int i;
	for(i=0;i<getdtablesize();i++)
	{
		close(i);
	}
	//打开文件
	FILE *fw=NULL;
	fw=fopen("time.log","a");
	if(NULL==fw)
	{
		perror("open error");
		return -1;
	}
	//写入文件
	time_t mytime;
	struct tm * pt=NULL;
	while(1)
	{
	time(&mytime);
	pt=localtime(&mytime);
	fprintf(fw,"%04d/%02d/%02d %02d:%02d:%02d",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);
	fflush(fw);
	sleep(1);
	}
	return 0;
}

进程间的通信
1.分类
早期unix进程间通信方式:POSIX提供的通信方式
无名管道:
有名管道:
信号:
systemV是当年非常流行的标准:
消息队列
信号量
共享内存
POSIX相对于systemV是比较新的标准,语法相对于简单
2.通信方式的各自特点
无名管道:速度慢,容量有限,只能用于父子间的通信,单工的,数据存在内存中
有名管道:任何进程间的通信,双工,有文件名,但速度慢
信号:唯一异步通信方式
消息队列:常用于cs模式中,按消息类型访问,
共享内存:效率最高,但是需要同步,互斥机制
信号量:不能传递复杂消息,一般和共享内存配合使用,使用同步
POSIX的unix间通信
1.无名管道
1.特点:
1.只能用于具有亲缘关系的进程之间的通信
2.单工的通信方式,具有固定的读端和写端
3.无名管道创建时会返回两个文件描述符,分别用于读管道和写管道
4.当管道中无数据时,读操作会阻塞,当管道中无空间时,写操作会阻塞.
5.当读端不存在,写管道,会出现管道断裂
在这里插入图片描述

2.案例:实现父子进程间的通信
在这里插入图片描述

父进程:
1.创建管道 ------读端和写端
2.创建子进程 ------继承管道的读端和写端
父进程:关闭写端
读取数据
通信结束,关闭读端
子进程:关闭读端
写入数据
通信结束,关闭写端
3.使用的函数
#include <unistd.h>
pipefd[0]----读管道
pipefd[1]----写管道
返回值:成功返回0,失败返回EOF
int pipe(int pipefd[2]);
无名管道在内存中存在,在OS下不可见,容量有限
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
在这里插入图片描述

4.获得无名管道的大小
在这里插入图片描述

5.无名管道使用时需要注意的问题
在这里插入图片描述

只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号(通常Broken pipe错误)。

6.验证管道是否断裂:
在这里插入图片描述

2.有名管道:
1.特点:

有名管道可以使互不相关的两个进程进行通信
打开管道时可指定读写方式
在文件系统可见,可以使用文件IO进行操作,严格遵循先入先出FIFO,无法使用lseek
当管道中无数据时,读操作阻塞,当管道中无空间时,写操作阻塞,通信结束,管道被清空
2.使用的函数:
#include <sys/types.h>
#include <sys/stat.h>
参数1:有名管道的管道名,在OS可见
参数2:创建方式 八进制
返回值:成功返回0,失败返回-1, 失败时若错误原因不是EEXIST,认为mkfifo(error)
int mkfifo(const char *pathname, mode_t mode);
3.案例:进程间的通信

在这里插入图片描述
在这里插入图片描述

作业:编写一子双工通信
进程A: 进程B
创建子进程 创建子进程
父进程 ----给B发 父进程:接送A
子进程 ----接送B 子进程:给A发

1.c

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define FIFO "a"
#define FIFOD "b"
int main(int argc, const char *argv[])
{
	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		if(mkfifo(FIFOD,0666)<0&&errno!=EEXIST)
		{
			perror("fifo error");
			return -1;
		}
		int fd=open(FIFO,O_RDONLY);
		if(fd<0)
		{
			perror("open error");
			return -1;
		}
		char buf[20]={'\0'};
		while(1)
		{
			memset(buf,'\0',sizeof(buf));
			printf("read:\n");
			read(fd,buf,sizeof(buf));
			printf("%s\n",buf);
		}
		close(fd);
	}
	else if(pid==0)
	{
		
		if(mkfifo(FIFO,0666)<0&&errno!=EEXIST)
		{
			perror("fifo error");
			return -1;
		}
		int fdd=open(FIFOD,O_WRONLY);
		if(fdd<0)
		{
			perror("open error");
			return -1;
		}
		char bufd[20]={'\0'};
		while(1)
		{
			printf("write:\n");
			scanf("%s",bufd);
			write(fdd,bufd,strlen(bufd));
		}
		close(fdd);
	}
	return 0;
}

2.c

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define FIFO "a"
#define FIFOD "b"
int main(int argc, const char *argv[])
{
	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		if(mkfifo(FIFO,0666)<0&&errno!=EEXIST)
		{
			perror("fifo error");
			return -1;
		}
		int fd=open(FIFO,O_WRONLY);
		if(fd<0)
		{
			perror("open error");
			return -1;
		}
		char buf[20]={'\0'};
		while(1)
		{
			printf("write:\n");
			scanf("%s",buf);
			write(fd,buf,strlen(buf));
		}
		close(fd);
	}
	else if(pid==0)
	{
		
		if(mkfifo(FIFOD,0666)<0&&errno!=EEXIST)
		{
			perror("fifo error");
			return -1;
		}
		int fdd=open(FIFOD,O_RDONLY);
		if(fdd<0)
		{
			perror("open error");
			return -1;
		}
		char bufd[20]={'\0'};
		while(1)
		{
			memset(bufd,'\0',sizeof(bufd));
			printf("read:\n");
			read(fdd,bufd,sizeof(bufd));
			printf("%s\n",bufd);
		}
		close(fdd);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值