目录
2,exec函数族 -----//在进程中加载另一个程序执行
一,进程相关概念
程序是语句的集合
进程是程序的一次执行过程。
每一个进程都有一个唯一的ID,可以通过getpid()获取
例如:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
while(1){
printf("%d\n",getpid());
sleep(1);
}
return 0;
}
进程和程序的区别
程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念
进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡
进程是系统分配资源的最小单位
线程是cpu调度的最小单位
二,进程的特征
动态性 -----是程序的执行过程
并发性 -----多个进程可以同时运行
独立性 -----系统给每一个进程会分配独立的虚拟空间
异步性 ----- 进程之间各自运行,不会干扰
三,进程的状态
参考:3_进程的状态.tif
四,进程种类
1,交互进程:
该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。
2,批处理进程:
该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。
例如: shell脚本程序
hello.sh
ls -l
pwd
touch abc.txt
3,守护进程:
该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。
五,进程系统调用
1,创建进程
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);//--子进程结束父进程再开始
pid_t fork(void);
//返回值--失败:-1,成功:给父进程返回子进程的ID,给子进程返回0 当调用fork()函数时,计算机会执行以下几步:
1》映射一个进程虚拟的内存空间,原来的进程称为父进程,新的虚拟空间中运行的进程称为子进程
2》将父进程所有数据段中的数据拷贝到子进程对应的段中
3》父子进程共享代码段
4》给父进程返回子进程的ID,给子进程返回0
5》父子进程从fork()函数调用的下一条语句同时开始运行。
例如:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}if(pid > 0){
//父进程执行
printf("我是老子,我的ID:%d\n",getpid());
while(1){
printf("没事生孩子!\n");
sleep(1);
}
}else{
//子进程执行
printf("我是儿子,我的ID:%d\n",getpid());
while(1){
printf("找个女朋友!\n");
sleep(1);
}
}
printf("hello world\n");
return 0;
}
2,exec函数族 -----//在进程中加载另一个程序执行
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, .../* (char *) NULL */);
int execlp(const char *file, const char *arg, .../* (char *) NULL */);
int execle(const char *path, const char *arg, .../*, (char *) NULL, 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[]);
//添加环境变量---export PATH=$PATH:环境变量路径
例如:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
if((pid = fork()) < 0){
perror("fork");
exit(1);
}else if(pid > 0){
while(1){
printf("this is parent process!\n");
sleep(1);
}
}else{
#if 0
execl("/bin/ls","ls","-l",NULL);
execlp("ls","ls","-l",NULL);
char * env[] = {"name=jack","passwd=123",NULL};
execle("./envtest","./envtest",NULL,env);
char *arg[] = {"ls","-l",NULL};
//execv("/bin/ls",arg);
//execvp("ls",arg);
#else
char *arg[] = {"./envtest",NULL};
char * env[] = {"name=jack","passwd=123",NULL};
execve("./envtest",arg,env);
#endif
//执行exec函数族后,后面的代码全部被加载的另一个程序替换,所以无法执行的
}
return 0;
}
//加载自己写的打印环境变量的程序,代码如下:
#include <stdio.h>
extern char **environ;
int main(void)
{
int i;
for(i = 0; environ[i]!= NULL; i++)
printf("%s\n",environ[i]);
return 0;
}
3、结束进程
#include <unistd.h>
void _exit(int status); //直接结束进程
例如:
int main(void)
{
printf("hello world");
_exit(0); //结束程序,不刷新缓冲区,所以hello world不能显示在屏幕上
return 0;
}
#include <stdlib.h>
void exit(int status); //结束进程之前,会先刷新缓冲区,并释放资源
例如:
int main(void)
{
printf("hello world");
exit(0); //结束进程之前,会先刷新缓冲区,并释放资源,所以hello world可以显示在屏幕上
return 0; //在main()函数中,执行return时,会自动调用exit();
}
4、获取进程的pid
#include <sys/types.h>
#include <unistd.h> pid_t getpid(void); //获取当前进程的pid
pid_t getppid(void); //获取当前进程的父进程pid
例如:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
printf("父进程ID = %d\n",getppid());
printf("进程ID = %d\n",getpid());
return 0;
}
5、进程收尸
#include <sys/types.h>
#include <sys/wait.h> // 给任意一个子进程收尸,哪个先结束就给哪个收尸
pid_t wait(int *wstatus);
//参数 ------ 获取子进程结束的状态
//返回值 ---成功:收尸的子进程pid,失败:-1
//当调用wait()给子进程收尸时:
1)如果父进程没有子进程,则wait()立即返回
2)如果子进程尚未结束,则wait()使父进程阻塞,直到有一个子进程结束时返回。
3)如果子进程已经结束,则wait()立即返回
例如:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
if((pid = fork()) < 0){
perror("fork");
exit(1);
}else if(pid > 0){
int wstatus;
//wait(NULL);
wait(&wstatus);
printf("%d\n",WEXITSTATUS(wstatus));
printf("helo world\n");
printf("父进程:pid = %d\n",getpid());
printf("父进程:ppid = %d\n",getppid());
}else{
printf("hello world\n");
printf("子进程:pid = %d\n",getpid());
printf("子进程:ppid = %d\n",getppid());
exit(89);
}
return 0;
}
//给指定的子进程收尸
pid_t waitpid(pid_t pid, int *wstatus, int options);
//参数1 ---- 指定的子进程pid:
pid > 0,给指定的子进程收尸
pid=-1:等待任何一个子进程退出,此时和wait作用一样。
pid=0:等待其组ID等于调用进程的组ID的任一子进程。
pid<-1:等待其组ID等于pid的绝对值的任一子进程。
//参数2 ---- 子进程结束状态
//参数3 ----- wait的选项,一般为0
//返回值 -----成功:收尸的子进程pid,失败:-1
例如:
int main(void)
{
pid_t pid1,pid2;
int i;
//创建子进程1
if((pid1 = fork()) < 0){
perror("fork");
exit(1);
}else if(!pid1){
//子进程1
for(i = 0; i < 5; i++){
printf("我是子进程1\n");
sleep(1);
}
exit(0);
}
//创建子进程2
if((pid2 = fork()) < 0){
perror("fork");
exit(1);
}else if(!pid2){
//子进程2
for(i = 0; i < 9; i++){
printf("我是子进程2\n");
sleep(1);
}
exit(0);
}
//父进程
waitpid(pid1,NULL,0);
printf("我是父进程!\n");
return 0;
}