进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元。
进程受系统内核管理,线程由进程创建和管理。
进程是放到磁盘的可执行文件,进程是指程序执行的实例。
进程是动态的,程序是静态的:进程不可复制移动,程序可以
进程是暂时的,程序是长久的:程序可以长期保存。
进程与程序组成不同:进程的组成包括程序,数据和进程控制块(即进程状态信息)
进程与程序的对应关系:通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。
进程的生命周期:创建,运行,撤销。每个进程由父进程创建,子进程也可以自己创建子进程。多个进程可以同时存在进程间可以通讯。进程可以被撤销,从而结束一个进程的运行。自己不可以清理进程表。
ps查看进程!查看后显示出来如下: pstree 进程以树的形状显示
pid=1;ppid=0;command=init 的进程(初始化进程)是所有用户进程的父进程。(他是用户进程的方式但是却有系统进程的身份。所有进程不能杀死他)。
撤销进程却没清理进程表中的进程号会产生僵尸进程,僵尸进程会占用进程表。
僵尸进程的产生:子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它父进程没有调用wait()或waitpid()函数来等待子进程的结束, 网络原因有时会引起僵尸进程;
僵尸进程的危害:僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能;
孤儿进程不会占用系统资源,最终是由init进程托管,由init进程来释放;
僵尸进程的处理:让僵尸进程成为孤儿进程,由init进程回收;(手动杀死父进程);调用fork()两次; 捕捉SIGCHLD信号,并在信号处理函数中调用wait函数;
任何一个进程都会经历僵尸进程阶段!父进程需要处理时间,这段时间撤销的时候就是僵尸进程
进程的状态:1.执行状态:进程正在占用CPU。2.就绪状态:不差条件只差CPU唤醒等待资源分配唤醒。3.等待状态:还差其他条件。
Linux系统是一个多进程的系统,具有并行性,互不干扰性。每个进程分配4G的虚拟空间。
进程ID:pid标识进程的唯一数字
父进程的ID(PPID),启动进程的用户ID(UID)
进程互斥:是指若有若干进程都要使用某一共享资源的时候,任何时刻最多允许一个进程使用,其他要使用该资源的进程必须等待,直到占用该资源者释放了该资源为止。
临界资源:操作系统中将一次只允许一个进程访问的资源称为临界资源。可以共享但同时只能一个人访问。临界区:程序中的一段代码,应保证诸进程互斥地进入各自的临界区。
同步:按照一定的顺序执行的过程称为进程的同步。具有同步关系一组并发进程称为合作进程,合作进程间互相发送信号称为消息或事件。
进程的调度:按照一定的算法,从一组待运行的进程中,选出一个来占有CPU运行。
调度方式:抢占式和非抢占式。抢占式可以让别人剥夺CPU使用权。调度算法对非抢占式无效,因为非抢占不放出自己的CPU。
高级调度。中级调度。低级调度。
调度算法:可见此博主:
(10条消息) 常用的调度算法(包含实例)|操作系统_taoxing-CSDN博客_调度算法甘特图
死锁:两个进程僵住都不能往前推进。互相占用了对方的资源
获取ID:
#include <sys/types.h>
#include <unistd.h> pid_t getpid(void) //获取本进程ID。
pid_t getppid(void) //获取父进程ID
例:getpid.c (演示)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
printf( "PID = %d\n", getpid() );
printf( “PPID = %d\n”, getppid() );
return 0;
}
创建进程:
#include<unistd.h>
pid_t fork(void) 功能:创建子进程,fork按照父进程的变量给子进程复制且分配空间。
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
/*此时仅有一个进程*/
pid=fork();
/*此时已经有两个进程在同时运行*/
if(pid<0)
printf("error in fork!");
else if(pid==0)
printf("I am the child process, ID is %d\n",getpid());
else
printf("I am the parent process,ID is %d\n",getpid());
}
fork的好处在于它被调用一次,却返回两次,它可能有三个不同的返回值,小于0失败,大于0返回父进程,返回0则是创建子进程。执行fork之前没有分配出子进程,后来才有的两个进程
输出两个,fork创建子进程所以会有父进程则是两个进程,所以输出了两个。
在pid=fork()之前,只有一个进程在执行,但在这条语句执行之后,就变成两个进程在执行了,这两个进程的共享代码段,将要执行的下一条语句都是if(pid==0). 两个进程中,原来就存在的那个进程被称作“父进程”,新出现的那个进程被称作“子进程”,父子进程的区别在于进程标识符(PID)不同.
#include <unistd.h>
#include <stdio.h>
int main(void)
{
pid_t pid;
int count=0;
pid = fork();
count++;
printf( “count = %d\n", count );
return 0;
}
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t pid;
int count=0;
pid=fork();
if (pid <0)
{
printf("fail\n");
}
else if (pid==0)
{
count++;
printf("child!%d\n",count);
}
else
{
count++;
printf("parent!%d\n",count);
}
return 0;
}
子进程的数据空间、堆栈空间都会从父进程得到一个拷贝,而不是共享。在子进程中对count进行加1的操作,并没有影响到父进程中的count值,父进程中的count值仍然为0
vfork:创建的子进程不复制父进程的变量。但他可以直接用父进程的变量。子进程先执行后父进程执行。fork的执行顺序无所谓。
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void)
功能:创建子进程
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t pid;
int count=0;
pid=vfork();
if (pid <0)
{
printf("fail\n");
}
else if (pid==0)
{
count++;
printf("child!%d\n",count);
}
else
{
count++;
printf("parent!%d\n",count);
}
exit(0);
}
return 0;释放参数,子进程释放了父进程的count导致段错误。 改成exit(0);结束进程。
还可以改成在子进程中加入 _exit(0); 子进程释放。
vfork 和fork的区别:
1. fork:子进程拷贝父进程的数据段 vfork:子进程与父进程共享数据段 2. fork:父、子进程的执行次序不确定 vfork:子进程先运行,父进程后运行
分析代码。
exec 函数族:exec代码后的代码不执行.exec用被执行的程序替换调用它的程序。
区别: fork创建一个新的进程,产生一个新的PID。exec启动一个新程序,替换原有的进程,因此进程的PID不会改变
#include<unistd.h>
int execl(const char * path,const char * arg1, ....)
参数:
path:被执行程序名(含完整路径)。
arg1 – argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。
如下:
#include<unistd.h>
int main()
{
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,NULL);
}
#include<unistd.h>
int execv (const char * path, char * const argv[ ])
参数:
path:被执行程序名(含完整路径)。
argv[]: 被执行程序所需的命令行参数数组。
代码如下:
#include <unistd.h>
int main()
{
char * argv[ ]={“ls”,”-al”,”/etc/passwd”,(char*)0}; execv(“/bin/ls”,argv);
}
#include <stdlib.h>
int system( const char* string )
功能:
调用fork产生子进程,由子进程来调用/bin/sh -c string来执行参数string所代表的命令
#include <stdlib.h>
int main()
{
system(“ls -al /etc/passwd”);
}
exec成功不返回,失败返回。exec只是执行新任务。exec后面的代码不会执行,system后面可以执行。
进程等待:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int * status)
功能: 阻塞该进程,直到其某个子进程退出。
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{ pid_t pc,pr;
pc = fork();
if(pc == 0){
printf(“This is child process with pid of %d\n”,getpid());
sleep(10); /* 睡眠10秒钟 */
}
else if(pc > 0){
pr=wait(NULL); /* 等待 */
printf("I catched a child process with pid of %d\n"),pr);
}
exit(0);
}
另一种进程等待:
pid_t waitpid(pid_t pid, int *status,int options)
pid<-1 等待进程组识别码为pid 绝对值的任何子进程.
pid=-1 等待任何子进程, 相当于wait().
pid=0 等待进程组识别码与目前进程相同的任何子进程.
pid>0 等待任何子进程识别码为pid 的子进程.
参数option 可以为0也可以为WNOHANG:如果没有任何已经结束的子进程则马上返回, 不予以等待.
option =0时是阻塞等待,option =WNOHANG时是非阻塞等待。