LINUX进程

1、LINUX进程:
进程是一个程序一次执行的过程,是操作系统动态执行的基本单元。进程的概念主要有两点:第一,进程是一个实体。每个进程都有自己的虚拟地址空间,包括文本区、数据区、和堆栈区。文本区域存储处理器执行的代码;数据区存储变量和动态分配的内存;堆栈区存储着活动进程调用的指令和本地变量。第二,进程是一个“执行中的程序”, 它和程序有本质区别。程序是静态的,它是一些保存在磁盘上的指令的有序集合;而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建、调度和消亡的过程,是 Linux 的基本调度单位。只有当处理器赋予程序生命时,它才能成为一个活动的实体,称之为进程。内核的调度器负责在所有的进程间分配 CPU 执行时间,称为时间片(time slice),它轮流在每个进程分得的时间片用完后从进程那里抢回控制权

2、进程的标识:
OS 会为每个进程分配一个唯一的整型 ID,做为进程的标识号(pid)。进程 0 是调度进程,常被成为交换进程,它不执行任何程序,是内核的一部分,因此也被成为系统进程。进程除了自身的 ID 外,还有父进程 ID(ppid),所有进程的祖先进程是同一个进程,它叫做 init 进程,ID 为 1,init 进程是内核自举后的一个启动的进程。init 进程负责引导系统、启动守护(后台)进程并且运行必要的程序。它不是系统进程,但它以系统的超级用户特权运行。

3、进程的状态
在这里插入图片描述
4、查看进程的状态的方法:
ps:查看活动进程。
ps –aux:查看各个进程状态,包括运行就绪等待等状态。
ps -aux| grep ‘aa’:查找指定(aa)进程。
ps –ef:查看所有的进程的 pid,ppid 等信息。
ps -aux 看%cpu(cpu 使用量) %mem(内存使用量)
stat 状态{S 就绪 T 中断 R 运行 Z 僵尸}


1、进程的创建
#include <unistd.h>
pid_t pid_t fork(void);
功能:对进程进行创建,创建了一个执行同一程序文本的进程但是他们在相同作用域部分的变量都是独立的,不是共享的。如何区分这两个进程?返回程序ID的值父进程,返回0的是子进程,负数表示创建进程失败。

pid_t vfork(void);
功能:创建子进程,这个子进程和父进程在相同作用域部分的变量都是共享的。子进程先于父进程执行,子进程执行exit()返回之后才会执行父进程

#include <stdio.h>
#include <unistd.h>
int main()
{
	pid_t ret=0;
	int a=0;
	ret=fork();
	if (ret<0) return 0; //创键失败,直接退出
	if(ret==0){ //子进程
		a+=20;
		printf("I am C a=%d\n",a);		
	}else{
		sleep(20);
		a+=40;
		printf("I am P a=%d\n",a);	
		
	}
	exit(0);
}

在这里插入图片描述
从上面的结果看,a的变量确实没有叠加,所以这两个进程的变量都是独立的;
接下来看一下vfork函数的。

#include <stdio.h>
#include <unistd.h>
int main()
{
	pid_t ret=0;
	int a=0;
	ret=vfork();
	if (ret<0) return 0; //创键失败,直接退出
	if(ret==0){ //子进程
		a+=20;
		printf("I am C a=%d\n",a);		
		sleep(5);
	}else{
		a+=40;
		printf("I am P a=%d\n",a);	
	}
	
	exit(0);
}

在这里插入图片描述
(注:上面的两个例子我都打印出a的地址,发现他们的地址都是一样的,估计这些地址应该只是虚拟地址而已,段基址应该不一样)


2、进程的终止
进程的终止有5种方式:
1)main函数的自然返回 2)调用exit函数 3)调用_exit()函数 4)接收到某个信号。如 ctrl+c SIGINT ctrl+\ SIGQUIT
5)调用 abort 函数,它产生 SIGABRT 信号,所以是上一种方式的特例。

在这里插入图片描述
3、 wait 和 waitpid 函数
用 fork 函数启动一个子进程时,子进程就有了它自己的生命并将独立运行。如果父进程先于子进程退出,则子进程成为孤儿进程,此时将自动被 PID 为 1 的进程(即 init)接管。孤儿进程退出后,它的清理工作有祖先进程 init 自动处理。但在 init 进程清理子进程之前,它一直消耗系统的资源,所以要尽量避免。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
wait 和 waitpid 都将暂停父进程,等待一个子进程退出,并进行清理工作;
wait 函数随机地等待一个子进程退出,并返回该子进程的 pid;
waitpid 等待指定 pid 的子进程退出;如果为-1 表示等待所有子进程,同样返回该子进程的 pid。
status 参数是传出参数,存放子进程的退出状态;通常用下面的两个宏来获取状态信息:
WIFEXITED(stat_val) 如果子进程正常结束,它就取一个非 0 值。
WEXITSTATUS(stat_val) 如果 WIFEXITED 非零,它返回子进程的退出码
options 用于改变 waitpid 的行为,其中最常用的是 WNOHANG,它表示无论子进程是否退出都将立即返回,不
会将调用者的执行挂起。

4、exec函数族
exec*由一组函数组成
extern char **environ;
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg , …, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char * path, char *const argv[], char *const envp[]);
exec 函数族的工作过程与 fork 完全不同,fork 是在复制一份原进程,而 exec 函数是用 exec 的第一个参数指定的
程序覆盖现有进程空间(也就是说执行 exec 族函数之后,它后面的所有代码不再执行)
path 是包括执行文件名的全路径名 file 既可是全路径名也可是可执行文件名
arg 是可执行文件的命令行参数,多个用,分割注意最后一个参数必须为 NULL。
argv 是一个字符串的数组 char *argv[]={“full path”,”param1”,”param2”,…NULL};
envp 指定新进程的环境变量 char *envp[]={“name1=val1”,”name2=val2”,…NULL};
exec 函数族的参数传递有两种方式:一种是逐个列举的方式,而另一种则是将所有参数整体构造指针数组传递。
在这里是以函数名的第 5 位字母来区分的,字母为“l”(list)的表示逐个列举的方式,其语法为 char arg;
字母为“v” (vertor)的表示将所有参数整体构造指针数组传递,其语法为
const argv[]。
以字母 p 结尾的函数通过搜索系统 PATH 环境变量来查找新程序的可执行文件的路径。如果可执行程序不
在 PATH 定义的路径中,我们就需要把包括目录在内的使用绝对路径的文件名作为参数传递给函数。
对有参数 envp 的函数调用,其以字母 e 结尾,函数通过传递 envp 传递字符串数组作为新程序的环境变量。
新进程中的全局变量 environ 指针指向的环境变量数组将会被 envp 中的内容替代。

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
	char *arrArg1[] = {"ls", "-l", NULL};
	char *arrArg2[] = {"get_arg", "abc", NULL};
	char *arrEnv[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
	int iRet = -1;
	iRet = system("ls -l");
	/* execl */
	//iRet = execl("/bin/ls", "ls", "-l", "/etc", NULL);//显示/etc 下
	//iRet = execl("/bin/ls", "ls", "-l", NULL); //显示当前
	//iRet = execl("/home/wangxiao/get_arg", "get_arg", "abc", NULL);//可执行程序
	/* execlp */
	//iRet = execlp("ls", "ls", "-l", NULL); //ls 在 PATH 路径中
	//iRet = execlp("get_arg", "get_arg", "abc", NULL);//错,当前路径不在 PATH 内
	//iRet = execlp("/home/wangxiao/get_arg", "get_arg", "abc", NULL); //加上路径
	/* execle */
	//iRet = execle("/bin/ls", "ls", "-l", NULL, arrEnv);
	//iRet = execle("/home/wangxiao/get_arg", "get_arg", "abc", NULL, arrEnv);
	/* execv */
	//iRet = execv("/bin/ls", arrArg1);
	//iRet = execv("/home/wangxiao/get_arg", arrArg2);
	/* execvp */
	//iRet = execvp("ls", arrArg1);
	//iRet = execvp("/home/wangxiao/get_arg", arrArg2);
	/* execve */
	//iRet = execve("/bin/ls", arrArg1, arrEnv);
	//iRet = execve("/home/wangxiao/get_arg", arrArg2, arrEnv);
	printf("iRet: %d\n",iRet);
	return 0;
}

5 system 函数
原型:
#include <stdlib.h>
int system(const char *string);
system 函数通过调用 shell 程序/bin/sh –c 来执行 string 所指定的命令,该函数在内部是通过调用 fork、
execve(“/bin/sh”,…)、waitpid 函数来实现的。通过 system 创建子进程后,原进程和子进程各自运行,相互间关联
较少。如果 system 调用成功,将返回 0。
示例:

	#include <stdio.h>
	#include <stdlib.h>
	int main()
	{
	system("ls -l"); //system(“clear”);表示清屏
	return 0;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值