34.Linux应用层开发--进程

引入:

今天开始学习linux应用层开发的必备知识,进程。我们之前的实时系统中,都是任务的概念,linux中也有任务概念,同时还有进程和线程,他们之间是什么关系呢?

 

其实在我们的windows中也有进程的概念,通过任务管理器就能查看到当前运行的进程。

开始学习之前先看下思维导图,把握这节的知识点,然后在进行详细的解读。

 

我们将上面的内容进行详细学习。

一.进程的基本知识

1.进程的概念

1>当我们打开windows时,说让你杀死一个进程,那什么是进程?

理解上,进行中的程序就是进程呗,程序的一次执行过程,是动态的(占用CPU和内存),包括创建,调度,执行和消亡。

2>那么和程序有啥区别?

很明显,程序是静态的,是存放在磁盘上的指令和数据的有序集合。

3>一个进程又包含哪些内容呢?

从我们的框图中也能清晰的看到,它包括进程控制块,也就是我们知道的PCB控制块,还要有cpu寄存器,堆栈,还有和程序中共有的部分,正文段,用户数据段,系统数据段。直接看框图更好理解

2.进程的特性:

1>并发性:多进程并发执行

2>动态性:进程状态不断变化

3>交互性:进程间交互,同步互斥等

4>独立性:地址空间相互独立

3.进程的类型

主要就是三大类型

1>交互式进程:典型的就是shell命令进程,可前台运行,也可以后台运行

2>批处理进程:与终端无关,作业队列中顺序执行,不需要很快响应,编译器的编译操作,数据库搜索等都属于批处理进程

3>守护进程:后台运行,系统进程都是以这种形式存在。

4.进程的状态:

运行态,等待态,停止态,死亡态。

 

二.进程的常见命令

我们对进程有了一点了解,那么我们还是要在终端上对进程进行一些操作,如查看一下状态啊等。

1.进程的查看,常用的几个命令

ps aux   查看所有进程信息,包括谁创建的,pid,cpu占用率,状态等

ps -elf

ps -elf|grep test 详细的查看某一个进程的信息

top  查看进程动态信息。

top |grep init  详细的查看某一个进程的动态信息

2.改变进程优先级

1> nice 按照用户指定的优先级运行(优先级范围-20--19)

例:

./test 然后通过ps -elf|grep test 查看test进程的信息,pid等。

nice -n 19 ./test 修改完后通过ps -elf|grep test 查看pid进程号,

然后top -p 10113(进程号),查看进程动态详细信息,发现进程优先级已经改成功

2>renice 运行态,改变正在运行的进程优先级

例:renice 10 10113 优先级就改变了。

3.进程的前后台操作

jobs查看后台几个进程

bg  将挂起的进程运行

fg 1 将后台进程放到前台运行

ctrl+z 前台变为后台,并停止。

三.进程的创建和结束及回收

1.进程创建

pid_t  fork(void); 一个fork会有两个返回值,通过不同的返回值得到父子进程,是个岔子函数。

失败:-1 父进程:返回子进程进程号  子进程:返回0

int main(){
	pid_t pid;
	int i;
	pid = fork();
	if(pid <0){
	    perror("fork");
	    return 0;
	}else if(pid==0){
		printf("son\n");
	}else{
		printf("father\n");
	
	}
	while(1) sleep(1);
}	

2.进程的结束

void  exit(int  status); 结束时会刷新缓冲区。

void  _exit(int  status); 结束当前进程并将status返回

3.父子进程关系

1> 子进程继承父进程内容

2> 父子进程有独立空间,互不影响

3> 若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变为后台进程

4> 若子进程先结束,父进程没有及时回收,子进程变为僵尸进程。

5> 子进程是从fork后开始运行,不是从main开始

6> 父子进程谁先运行依赖于操作系统调度策略

7>父子进程可以多次创建

4.进程的回收

子进程结束时由父进程回收,若不及时回收就会出现僵尸进程。

孤儿进程由init 进程回收。

1> pid_t wait(int *status)

成功:子进程进程号 失败:EOF

子进程没有结束,父进程一直阻塞

status为NULL表示直接释放进程PCB,不接收返回值(不接收遗言)

2> pid_t waitpid(pid_t pid,int *status,int option)

指定回收哪一个子进程。option 指定回收方式

3>通过以下几个宏定义,可以判断子进程是什么原因死的

WIFEXITE(status)判断子进程是否正常结束

WEXITSTATUS(status)获取子进程返回值

WIFSIGNALED(status)判断子进程是否被信号结束

WTERMSIG(status)获取结束子进程的信号类型

int main(){
	pid_t pid;
	int i;
	int status;

	pid = fork();
	if(pid <0){
		perror("fork");
		return 0;
	}else if(pid==0){
		printf("bbbbbb\n");
		sleep(2);
		exit(2);
	}else{
		printf("aaaaaa\n");
		//wait(&status); //回收进程
		sleep(4);
	    waitpid(pid,&status,WNOHANG); //回收指定进程
    	printf("st=%d\n", WEXITSTATUS(status));

	}
	
	while(1) sleep(1);
	return 0;
	
}

四.exec函数族

为了实现父子进程执行不同的程序,exec函数族就是为了执行第三方程序。

以下几个函数都是为了执行第三方程序,只是操作方式不一样。

int execl(const char *path, const char *arg, …);

  if(execl("/bin/ls", "ls", "-a", "-l", "./", NULL) < 0) {
     perror("execl");
  } 

int execlp(const char *file, const char *arg, …);

  if(execlp("ls", "ls", "-a", "-l", "./", NULL) < 0) {
     perror("execl");
  }  //从path路径下查找文件

int execv(const char *path, char *const argv[]);

  char  *arg[] = {"ls", "-a", "-l", "./", NULL};
  printf("aaaaaaaaaaah\n");
  if  (execv("/bin/ls", arg) < 0) {
     perror("execv");
  } 

int execvp(const char *file, char *const argv[]);

  char  *arg[] = {"ls", "-a", "-l", "./", NULL};
  printf("aaaaaaaaaaah\n");
  if  (execvp("ls", arg) < 0) {
     perror("execv");
  } 

上面几个函数执行了第三方函数,但是自己的函数也不能丢啊,就有了system函数

int system(const char *command);

system("ls -l -a ./");  

相当于把exec函数进行了封装,fork了一个进程,子进程exec执行操作,父进程阻塞等待子进程结束后,继续执行

不替换程序内容。

五.守护进程

作为三大进程之一,重要性自然不必多说,那么什么是守护进程,又如何创建呢??

1.守护进程特点

始终后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。

一般的进程关闭会话后,所有进程就会结束。

2.守护进程的创建过程

1>先与终端脱离关系,让子进程变为孤儿进程。

2>子进程创建一个新的会话,并成为新的会话组长。

3>守护进程一直在后天运行,其工作目录不能被卸载,重新设定当前目录(假如是临时目录,容易出现问题,所以更改目录,路径不限定)

4>改变文件掩码,防止设置权限时受影响

5>关闭所有从父进程继承的打开文件

最后查看编写的程序是否为后台程序,关闭终端后是否会影响进程。

只能用kill杀死进程。

创建一个守护进程,将系统时间保存到log文件中

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(){
	pid_t pid;
	
	pid = fork();
	if(pid<0){
		perror("fork");
		return -1;
	}else if(pid>0){
		exit(0);
	}
	
	pid = setsid();
	if(pid==-1){
		perror("setsid");
		return -1;
	}
	
	chdir("/");
	
	umask(0);
	int i;
	for(i = 0;i<2;i++){
		close(i);
	}
	
	FILE *fp;
	time_t ctm;
	fp = fopen("1.log","w");
	while(1){
		ctm = time(NULL);
		fputs(ctime(&ctm),fp);
		fflush(fp);
		sleep(1);
	}
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章