Linux多任务机制
并发执行和并行执行(重点)
并发执行:并不是真正意义上的同时运行,而是通过时间片轮转机制,谁先抢到cpu资源系统会分配时间片,时间片递减,时间片很短,频繁切换给人的感觉是同时运行
并行执行:多个cpu,可以达到真正同时运行多个任务
进程
(1)进程是一个程序的动态执行过程;
(2)进程是一个独立可被调用的任务;
(3)进程是操作系统资源分配和调用的基本单位;
进程的状态
就绪态---运行态---阻塞态
进程和程序的区别(重点)
程序是一段静态的代码,是保存在计算机上的指令和数据的有序集合,没有任何执行的概念
进程是一个动态的概念,它是程序的一次动态执行过程,包括动态创建、调度、执行和消亡的整个过程,是程序执行和资源管理的最小单位。
进程的相关命令
静态显示进程相关信息 ps aux
动态显示进程的相关信息 top
列出进程关系树 pstree
杀死进程 kill pid
pid=1的是init进程 老祖先,老宝贝
查看进程的pid号
pid号是Linux内核进程的唯一标识符;
#include "my.h"
int main()
{
printf("当前进程的pid = %d\n",getpid());
printf("当前进程的父进程的pid = %d\n",getppid());
return 0;
}
系统中可创建的进程数目是有限的,查看上限用
cat /proc/sys/kernel/pid_max
创建进程
fork函数
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:用于创建一个子进程,当执行完fork函数就会出现一个新的进程,这个新的进程就称为子进程,原来的进程称为父进程,fork函数执行完子进程几乎会复制父进程的全部内容,(堆区、栈区、全局区、代码段。。),并且子进程从fork的下一行代码开始执行。
返回值:fork函数调用成功,返回两次
返回值为0,代表当前进程是子进程
返回值为非负数,代表当前进程为父进程
调用失败,返回-1
#include "my.h"
int main()
{
pid_t ret = fork();
if(ret == -1) //创建子进程失败
{
perror("fork failed");
return -1;
}
else if(ret == 0) //子进程在运行
{
printf("child ret is %d\n",ret);
printf("子进程的PID = %d,子进程的父进程PID = %d\n",getpid(),getppid());
}
else if(ret > 0) //父进程在运行
{
sleep(1); //保证子进程先被运行
printf("parent ret is %d\n",ret);
printf("父进程的PID = %d,父进程的父进程PID = %d\n",getpid(),getppid());
}
//父子进程都执行的操作放到分支外
printf("hello world\n");
return 0;
}
结束进程
exit函数
#include <stdlib.h>
void exit(int status);
功能:结束当前进程,在进程结束前会刷新缓存区,关闭一些打开IO流stdout stdin stderr。
参数:int status 是一个整型的参数,可以使用这个参数来传递进程结束时的状态。通常0代表正常结束。
调用:exit(0); 0正常结束,结束前会刷新缓存区
exit(-1); -1异常结束,结束前会刷新缓存区
countine 结束本次循环
break 结束当前循环
return 结束的是函数
exit 结束当前进程
_exit函数
#include <unistd.h>
void _exit(int status);
功能:结束当前进程,不刷新缓存区。
参数:int status 是一个整型的参数,可以使用这个参数来传递进程结束时的状态。通常0代表正常结束。
调用:_exit(0); 0 正常结束 执行_exit()函数后,不会刷新缓存区,直接结束进程
_exit(-1); -1 异常结束 执行_exit()函数后,不会刷新缓存区,直接结束进程
exit和_exit函数的区别(重点)
(1)exit和_exit函数都是结束进程的;
(2)exit函数结束进程前刷新缓存区,_exit函数结束进程前不刷新缓存区。
孤儿和僵尸进程
孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的生命,此时子进程叫做孤儿进程。 Linux避免系统出现过多的孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。
僵尸进程
子进程结束了,但父进程未调用wait族函数对子进程收尸(回收资源)。避免僵尸进程尽量在子进程结束时为其收尸。
回收进程资源
在进程结束时父进程调用wait或waitpid回收子进程资源。
wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:阻塞等待子进程结束,子进程结束时解除阻塞。
参数:整数指针来获取进程结束的状态,但通常会忽略;
返回值:成功,返回pid_t
失败,返回 -1
调用:
wait(NULL); 忽略子进程结束时的状态直接回收资源
int status ; 随机数
wait(&status); 通过参数地址传递获取子进程结束的状态,并回收资源
waitpid函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:指定等待那个子进程结束,当这个子进程结束时为其回收资源。
参数:pid_t pid //pid 1234
int *status //状态通wait函数的参数意义一样 用来获取子进程结束的状态
int options://选项 WNOHANG是Wait No Hang 的缩写。
返回值:大于0,指定等待的子进程结束了,子进程pid;
等于0,WNOHANG不阻塞,此时返回值为0代表没有子进程结束;
-1,出错了
waitpid(1234, NULL, 0);
第三个参数值是0时代表阻塞等待pid为1234的子进程结束
waitpid(5678, NULL, WNOHANG);
第三个参数是WNOHANG时代表不阻塞等待子进程5678的子进程结束
例子
#include "my.h"
int main()
{
pid_t ret = fork();
if(ret == -1) //创建子进程失败
{
perror("fork failed");
return -1;
}
else if(ret == 0) //子进程在运行
{
printf("child running\n");
sleep(1);
}
else if(ret > 0) //父进程在运行
{
waitpid(ret,NULL,0); //第3个参数0代表阻塞等待子进程
printf("parent running\n");
}
return 0;
}
wait与waitpid的区别
wait使用调用者阻塞,waitpid有一个选项,可以使调用者不堵塞
exec族函数
为什么要用exec族函数,有什么作用?
1、一个父进程希望自己复制自己,使父子进程同时执行不同的代码段。
2、一个进程要执行一个不同的程序。
(2条消息) linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_云英的博客-优快云博客_linux execl函数
守护进程
linux中后台服务进程,它是一个生命周期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些事件。守护进程常常在系统启动时开始执行,在系统关闭时终止。
查看守护进程的命令 ps ajx
编写守护进程(重点)
(1)创建子进程,父进程退出(孤儿进程)
(2)在子进程创建新的会话 setsid()
(3)修改当前目录 chdir()
(4)重设文件权限掩码 umask(0)
(5)关闭文件描述符
int num = getdtablesize(); 获取当前进程的文件描述符表的大小
for(int i = 0;i < num; i++)
close(i);
#include "my.h"
int main()
{
pid_t ret = fork();
if(ret == -1)
{
perror("fork failed");
exit(-1); //结束进程
}
else if(ret > 0) //父进程
{
//(1)创建子进程,父进程结束形成孤儿进程
exit(0);
}
else if(ret == 0) //子进程
{
//(2)创建新会话
setsid();
//(3)修改当前目录
chdir("/home/zt/Public"); //修改当前目录为Public
//(4)重设文件权限掩码
umask(0);
//(5)关闭文件描述符
int num = getdtablesize(); //获取文件描述的大小
int i;
for(i = 0;i < num;i++)
{
close(i);
}
//创建守护进程要做的操作
int fd = open("./daemon.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
time_t t;
char buf[100] = {0}; //用于保存英文格式系统时间
while(1)
{
time(&t); //获取秒数
sprintf(buf,"%s",ctime(&t)); //将英文格式的时间保存到缓存区
write(fd,buf,strlen(buf));
sleep(2);
}
close(fd);
}
return 0;
}