操作系统--进程

什么是进程

概念:一个正在执行的程序,包含多个资源
{
    标识符:用于区别于其他进程
    状态:若进程正在执行,则进程处于执行态
    优先级:相对于其他程序的优先级
    程序计数器:程序中即将被执行的下一条指令的地址
    内存指针:程序代码和进程相关数据的指针,还有和其他进程共享内存的指针
    上下文数据:程序执行时处理器的寄存器中的数据
}
上述信息存放在进程控制块中(PCB) task_struct
操作系统是通过双向链表来组织所有PCB。

进程的运行状态

新建-就绪=运行-退出
            |    /
           阻塞

进程的创建过程

写时拷贝技术:传统的fork()直接将所有资源复制给新创建的进程,这种简单但是效率低下,若新进程要立即执行新的映像那么前面的拷贝都是白费,写时拷贝是推迟甚至免除拷贝的技术,当创建新进程的时候首先让父子进程共享同一块内存,当某一方需要进行修改时,数据才会被拷贝,所以fork()开销仅仅是分配的唯一进程描述符。
fork()和vfork()的区别:vfork不会讲父进程的地址空间完全复制给子进程,当子进程调用exec或exit之前,子进程在父进程空间执行,故比fork效率高;vfork会保证子进程先运行,在子进程执行exit或exec后,父进程才会被调度执行。
步骤:
1.为新进程分配一个唯一的进程标识号。
2.给进程分配空间。
3.初始化进程控制块,进程标识号包括进程ID和其他相关ID,处理器状态信息初始化为0。
4.设置正确的连接,新进程处于就绪/挂起链表中
5.创建或扩充其他数据结构。
fork浅拷贝的原因:
在这里插入图片描述
https://blog.csdn.net/xuzhangze/article/details/79754853

进程切换(用户态到内核态的切换)

方式原因使用例子
中断当前指令的外部执行对异步外部事件的反应完成一次I/O操作
异常与当前的指令执行有关处理一个错误或异常条件缺页异常
系统调用显示调用调用操作系统函数open()

僵死进程以及处理方式

产生原因:父进程未结束,子进程结束,并且父进程未读取子进程的退出状态,仅有子进程的主题空间被释放,但是PCB未释放。
处理方式:
1.父进程调用wait或waitpid获取子进程的退出状态,这样会导致父进程在wait或waitpid调用后阻塞运行,直至子进程退出。
2.父进程调用signal(SIGCHLD,SIG_IGN),来忽略SIGCHLD信号,这样子进程结束后会由内核释放资源。
3.对子进程的退出捕获他们的退出信号SIGCHLD,在信号处理函数调用wait或waitpid来释放他们的资源。
会对系统产生影响:不释放PCB则进程号会一直被占用,当系统有大量僵死进程时,会因为没有可用的进程号而无法产生新的进程。

孤儿进程

概念:父进程结束,子进程未结束。孤儿进程会被系统进程(init进程)接管,负责进程的资源释放。
会对系统产生影响:孤儿进程会由init进程进行正常的资源释放,所以不会对系统产生危害。

守护进程以及编程方式

概念:在系统启动时自启(init进程一般是守护进程的父进程),在系统关闭的时候终止,生存周期长,一般在后台运行,可通过ps -axj查看系统守护进程。
编程方式
1.首先调用umask将文件模式创建屏蔽字设置为0。
2.调用fork(),然后使父进程退出(exit),实现了以下目的,第一,若守护进程是作为简单shell命令启动的,那么父进程的终止会使shell认为这条命令执行结束;第二子进程继承了父进程的组ID,保证了子进程不会是一个进程组的组长进程,这是为setsid调用做前提条件。
3.调用setsid创建新会话,①成为新会话的首进程②成为新进程组的组长进程③没有控制终端
4.将工作目录更改为根目录
5.关闭不需要的文件描述符,使守护进程不会再拥有从父进程继承来的某些文件描述符使用open_max或getrlimit函数获取最高文件描述符值,然后循环关闭到该值。
6.某些守护进程打开/dev/null 使其具有文件描述符0,1,2,这样任何一个试图读标准输入,写标准输出或标准出错的库例程不会产生任何结果。
守护进程示例

#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>
void daemonize(const char *cmd)
    {
        int                  i, fd0, fd1, fd2;
        pid_t                pid;
        struct rlimit        rl;
        struct sigaction     sa;
     //清除文件创建掩码
        umask(0);
    //获取最大数量的文件描述符
        if(getrlimit(RLIMIT_NOFILE, &rl) < 0)
            err_quit("%s: can't get file limit", cmd);
    //成为失去控制终端的会话负责人
        if((pid = fork()) < 0)
            err_quit("%s: can't fork", cmd);
        else if (pid != 0)    /* parent */
            exit(0);
        setsid();
        
    //确保未来的开放不会分配控制终端
        sa.sa_handler = SIG_IGN;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        if(sigaction(SIGHUP, &sa, NULL) < 0)
            err_quit("%s: can't ignore SIGHUP");
        if((pid = fork()) < 0)
            err_quit("%s: can't fork", cmd);
        else if( pid != 0 )    /* parent */
            exit(0);
    
    //将当前工作目录更改为root,这样我们就不会阻止卸载文件系统
        if(chdir("/") < 0)
            err_quit("%s: can't change directory to /");
        
    // 关闭所有打开的文件描述符
        if(rl.rlim_max = RLIM_INFINITY)
            rl.rlim_max = 1024;
        for(i = 0; i < rl.rlim_max; i++)
            close(i);
    
    //将文件描述符0,1和2附加到/dev/null
        fd0 = open("/dev/null", O_RDWR);
        fd1 = dup(0);
        fd2 = dup(0);
    
    // 初始化日志文件
        openlog(cmd, LOG_CONS, LOG_DAEMON);
        if(fd0 != 0 || fd1 != 1 || fd2 != 2)
        {
            syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2);
            exit(1);
        }
    }

转自《UNIX环境高级编程》第十三章

进程替换(exec函数族的使用)

功能:调用它并不会产生新的进程,一个进程一旦调用exec函数,它本身如同死亡了一样,系统会将代码段替换成新的程序代码,唯一保留一个进程的ID,对于系统来说还是同一个进程,只不过干的另一件事情。
注意点:在使用exec函数之前,首先使用fork函数创建一个子进程,子进程调用exec函数。
具体函数:
int ececv(const char *path, char *const argv[]);
通过路径名方式调用可执行文件作为新的进程映像。
int execl(const char path, const char arg,…);
与execv函数的用法类似,只是在传递argv参数的时候每个命令行参数都声明为单独的参数,最后要以NULL指针结束。
int execve(const char
pathname,const char
argv[], char *constebvp[]);
patrhnam是执行程序的路径名,参数argv、envp与main函数的argv、envp对应-系统调用函数
int execlp(const char *file, const char *argv,…);
与execl函数类似
int execvp(const char *file, const char *const argv[]);
与execv函数类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值