目录
1.进程的定义
- 进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元;
- 系统内核创建进程。系统内核管理进程
- 进程创建线程,进程管理线程
2.进程与程序
- 程序是放到磁盘的可执行文件
- 进程是指程序执行的实例
- 进程是动态的,程序使静态的:程序是有序代码的集合;进程是程序的执行。通常进程不可在计
算机之间迁移;而程序通常对应着文件、静态和可以复制 - 进程是暂时的,程序使长久的:进程是一个状态变化的过程,程序可长久保存
- 进程与程序组成不同:进程的组成包括程序、数据和进程控制块(即进程状态信息)
- 进程与程序的对应关系:通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可
包,括多个程序.
3.进程的生命周期
-
创建
每个进程都是由其父进程创建进程可以创建子进程,子进程又可以创建子进程的子进程
init初始化进程;第一个用户进程,由系统进程产生,是所有用户进程的父进程
-
运行
多个进程可以同时存在进程间可以通信
-
撤销
进程可以被撤销,从而结束一个进程的运行。
不能删除进程表信息,进程表信息由进程的父进程删除,不删形成僵尸进程
4.僵尸进程
- 僵尸进程的产生:如果一个进程已经终止,但是它的父进程尚未调用 wait() 或 waitpid() 对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(zombie process)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。
- 僵尸进程的危害:
在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 PID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。
如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
- 僵尸进程的消除:
僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过 wait() 来避免僵尸进程的产生。
当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。
5.孤儿进程
- 在一个父进程退出后,剩余的它的一个子进程或者多个子进程仍然在运行,并没有退出,那么这些子进程就会变成孤儿进程,这些孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
6.进程的状态
- 执行状态:进程正在占用CPU
- 就绪状态:进程已具备一切条件,正在等待分配CPU的处理时间
- 等待状态:进程不能使用CPU , 若等待事件发生则可将其唤醒
7.Linux进程
- Linux系统是一个多进程的系统,它的进程之间具有并行性、互不干扰等特点。也就是说每个进程都是一个独立的运行单位,拥有各自的权利和责任。其中,各个进程都运行在独立的虚拟地址空间,因此,即使一个进程发生异常,它也不会.影响到系统中的其他进程。
8.Linux下进程地址空间
9.进程ID
PID:当前进程id getpid()
PPID:当前进程父进程id getppid()
UID:用户id, 也就是该进程的所有者id
euID:有效用户id
uid为文件的执行者,而euid为文件的所有者,ps命令中看到的用户为文件的所有者。
10.进程互斥
- 进程互斥是指当有若干进程都要使用某一共享资源时,任何时刻最多允许一个进程使用,其他要使用该资源的进程必须等待,直到占用该资源者释放了该资源为止
11.临界资源
- 操作系统中将一次只允许一个进程访问的资源称为临界资源
-
临界区
进程中访问临界资源的那段程序代码称为临界区为实现对临界资源的互斥访问,应保证诸进程 互斥地进入各自的临界区
12.进程同步
- 一组并发进程按一定的顺序执行的过程称为进程间的同步
- 具有同步关系一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件
13.进程调度
- 概念:
按一定算法,从一组待运行的进程中选出一个来占有CPU运行。
- 调度方式:
- 抢占式
- 非抢占式
- 调度算法
- 先来先服务调度算法
- 短进程优先调度算法
- 高优先级优先调度算法
- 时间片轮转法
14.死锁
- 多个进程因竞争资源而形成一种僵局若无外力作用,这些进程都将永远不能再向前推进
15.创建进程
- #include <unistd.h>
pid_t fork(void)
功能:创建子进程
fork的奇妙之处在于它被调用一次,却返回两次,它可能有三种不同的返回值:
-1失败 >0父进程 0子进程
- 在pid=fork()之前,只有一个进程在执行,但在这条语句执行之后,就变成两个进程在执行了,这两个进程的共享代码段,将要执行的下一条语句都是if(pid==0). 两个进程中,原来就存在的那个进程被称作“父进程”,新出现的那个进程被称作“子进程”,父子进程的区别在于进程标识符(PID)不同.
- #include <sys/types.h>
#include <unistd.h>
pid_t vfork(void)
功能:创建子进程
- 区别:
1. fork:子进程拷贝父进程的数据段
vfork:子进程与父进程共享数据段
2. fork:父、子进程的执行次序不确定
vfork:子进程先运行,父进程后运行
子进程执行新任务,父进程子进程并发运行
- exit()
头文件:<stdlib.h>
功能:结束进程
清空文件缓冲去
- _exit()
头文件:<unistd.h>
功能:结束进程
不清空文件缓冲区
16.exec函数族
- exec用被执行的程序替换调用它的程序。
区别:fork创建一个新的进程,产生一个新的PID。exec启动一个新程序,替换原有的进 程,因此进程的PID不会改变
- #include<unistd.h>
int execl(const char * path,const char * arg1, ....)
参数:
path:被执行程序名(含完整路径)。
arg1 – argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。
返回值:成功不返回,失败返回-1
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int pid;
pid = fork();
if(pid < 0)
{
perror("fork fail\n");
exit(-1);
}
else if(pid > 0)
{
int i;
for(i = 0; i < 3; i++)
{
sleep(1);
printf("父进程!\n");
}
}
else
{
execl("./main","main","1","2","3",NULL);
}
return 0;
}
- int execv (const char * path, char * const argv[ ])
1) excC---中的v是指vector向量-- -将各种命令参数放进数组里将数组带回来,这个数组是
指针数组,每个指针指向一个字符串
2)第一个参数path:被执行程序名(含完整路径)
3) argv[]:被执行程 序所需的命令行参数数组。以空指针(NULL) 结束。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
pid_t pid;
pid = fork();
int i;
if(pid < 0)
{
perror("fork error!\n");
exit(-1);
}
else if(0 == pid)
{
// execl("./main","main","1","2","3",NULL);
char * argv[] = {"./main","main","1","2","3",(char*)0}
execv("./main",argv);
return 0;
}
- int execlp(const char * file, const char * arg......
1).上述execlp中的p是path, 即路径,因此第一个参数只要写文件就行, 不需要再写路径
2)这个路径可以寻找任何系统路径,但如果是该程序是自己写的,不是系统命令,就需要用
execl
3)其他内容和execl一样
- int execvp(const char * file, const char * argv[])
1) . 上述execlp中的p是path,即路径,因此第一个参数只要写文件就行, 不需要再写路径
2)其他内容参考execv
- int execle(const char *path,const char * arg.......nst char *env[])
1) char* env]:环境变量,多加了一个环境变量
2)其他内容和execl 一样
- int execve(const char *path,const char * argV[],const char * env[])
1) char * env]:环境变量,多加了一个环境变量
2)其他内容和execv 一样
- #include <stdlib.h>
int system( const char* string )
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
pid_t pid;
pid = fork();
int i;
if(pid < 0)
{
perror("fork error!\n");
exit(-1);
}
else if(0 == pid)
{
// execl("./main","main","1","2","3",NULL);
// char * argv[] = {"main","1","2","3",(char*)0};
// execv("./main",argv);
system("./main 1 2 3");
printf("*****************************\n");
}
else
{
for(i =0; i < 3;i++)
{
sleep(1);
printf("我是你爹!\n");
}
}
return 0;
}
17.进程等待
- #include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int * status)
功能:阻塞该进程,直到其第一个子进程退出。
pid_t waitpid(pid_t pid , int *status , int options)
pid参数
pid < -1 :取负数绝对值,看哪一个进程组的pid等于该负数的绝对值,等待该进程组
pid = -1:等第一个结束进程,相当于wait
pid = 0 :等当前进程组的其他进程
pid > 0:等指定的
options参数
0:阻塞
WNOHANG:非阻塞
返回值:
0:仅当options为非阻塞时出现,表示本应等待,却没有等待,否则不会返回0
-1 错误
没有pid
该pid不是你的子进程
等待成功返回等待进程的pid