Linux进程相关

进程

一、什么是进程?

    1、从用户角度:进程是程序的一次动态执行过程。
    2、从操作系统角度:进程是操作系统分配内存,时间片等资源的基本单位
    3、进程是操作体统可分配资源的最小单位,且每个进程都有自己独立的地址空间和执行状态

二、进程数据结构

    1、PCB:用于描述进程状况以及控制进程运行的全部信息
    2、数据段:程序运行时需要的数据
    3、代码段:编译后形成的一些指令
    4、堆栈段:程序运行时动态分配的一些内存

三、进程与程序的异同

    1、进程是动态的,而程序是静态的;
    2、一个进程只能对应一个程序,而一个程序可以对应多个进程;

四、进程的状态

    1)、进程的三种基本状态
        a、就绪(Ready)状态
                当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,
        这时的进程状态称为就绪状态。
        b、执行(Running)状态
                当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状
        态。
        c、阻塞(Blocked)状态
                正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻
        塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、
        等待信件(信号)等。

    2)、Linux中进程状态
        a、运行状态(TASK_RUNNING):是运行态和就绪态的合并,表示进程正在运行                     
              或准备运行,Linux 中使用TASK_RUNNING 宏表示此状态
        b、可中断睡眠状态(浅度睡眠)(TASK_INTERRUPTIBLE):进程正在睡眠(被阻
             塞),等待资源到来是唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行
             队列。Linux 使用TASK_INTERRUPTIBLE 宏表示此状态。
        c、不可中断睡眠状态(深度睡眠状态)(TASK_UNINTERRUPTIBLE):
             其和浅度睡眠基本类似,但有一点就是不可被其他进程信号或时钟中断唤醒。
             Linux 使用TASK_UNINTERRUPTIBLE 宏表示此状态。
        d、暂停状态(TASK_STOPPED):进程暂停执行接受某种处理。如正在接受调试的
              进程处于这种状态,Linux 使用TASK_STOPPED 宏表示此状态。
        e、僵死状态(TASK_ZOMBIE):进程已经结束但未释放PCB,Linux 使用
             TASK_ZOMBIE 宏表示此状态

五、相关函数

  1)、子进程的创建
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

返回:
成功子:进程中为0,父进程中为子进程ID (可类比链表)
失败:-1
详解:
1、fork出的子进程继承父进程的整个地址空间,如图:

在这里插入图片描述

由此可见,fork出的子进程将得到父进程的一个拷贝,因此在子进程上修改数据不会影响到父
进程。实际上由于fork之后经常跟随着 exec。作为替代,现在的实现是使用了在写时复制( 
Copy-On-Write, COW)的技术。这些区域由父、子进程共享,而且内核将它们的存取许可权
改变为只读的。如果有进程试图修改这些区域,则内核为有关部分,典型的是虚存系统中
的“页”,做一个拷贝。
	2、fork之后,父子进程都将从fork之后的代码开始执行
	3、fork之后,父子进程共享文件,也就是说任一进程修改文件都会是文件表中的信息被修改。

在这里插入图片描述

	4、另一个进程创建函数
#include <sys/types.h>
#include <unistd.h>

pid_t vfork();   ---不推荐使用
vfork()同样是创建子进程,但区别在于,vfork()保证子进程先运行,在它调用exec或exit之后
父进程才被调度。vfork()设计出来的目的是exec一个新程序,因此它并不将父进程的地址空间
完全复制到子进程。(vfork 是在fork 没有实现COW时,为避免exec而造成地址空间浪费而
设计出来,早先的fork总是会对父进程的地址空间进行拷贝)

2)、进程的终止
     1、 正常终止: 
            a) 在main函数内执行return语句。(这等效于调用exit)
            b) 调用exit函数。此函数由ANSI C定义,其操作包括调用各终止处理程序(终止处
                理程序 在调用atexit函数时登录),然后关闭所有标准I / O流等。 
            c) 调用_exit系统调用函数。
     2、 异常终止:
            a) 调用abort。它产生SIGABRT信号,所以是下一种异常终止的一种特例。 
            b) 当进程接收到某个信号时。

     3、相关函数
#include <stdlib.h>
void exit(int status);
int atexit(void (*function)(void));    //1、用于注册终止处理函数,由exit()调用;
                                       //2、子进程继承父进程注册的处理函数;
                                       //3、atexit注册的函数中有一个没有正常返回被
                                       //kill,则后续的注册函数都不会被执行。
----------------------------------------------------------------------
#include <unistd.h>
void _exit(int status);

exit和_exit的区别 :在这里插入图片描述

    从图中可直观的看到exit在结束调用它的进程之前会先执行终止处理函数,
    再执行标准I/O清除,但最终都会执行_exit来进入内核,清除其使用的内存
    空间,并销毁其再内核中的各种数据结构。
    
    3)、wait函数(父进程查询子进程的退出)
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);

返回
成功:进程ID
失败:-1
   1、僵尸进程
    在介绍wait和waitpid的功能之前先来看看僵尸进程的含义:
    当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常 地结束运行,或者父进程调用了wait才告终止。
    子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。
    进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵尸进程”,用ps查看会以“Z”表示。
    避免方式:
    a、调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。
    b、如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);
         表示父进程忽略SIGCHLD信号(子进程退出时,内核会向父进程发送SIGCHLD),该
         信号是子进程退出的时候向父进程发送的。此处的SIG_IGN尽管也是忽略,但与
        SIGCHLD的默认忽略SIG_DEF不同,SIG_IGN会将僵尸进程转交给init进程处理,从而
        避免僵尸进程。
    2、函数详解
        参数:statloc:状态指针,指向的内存表示终止进程的终止状态,可设置为NULL
                   pid:指定进程 ----  a、pid == -1 等待任一子进程。于是在这一功能方面
                                                        waitpid与wait等效。 
                                                  b、pid > 0 等待其进程I D与p i d相等的子进程。 
                                                  c、pid == 0 等待其组I D等于调用进程的组I D的任一子
                                                       进程。
                                                  d、pid < -1 等待其组I D等于p i d的绝对值的任一子进
                                                        程。

                   options: WNOHANG      ----  不阻塞,此时返回0
                                    WUNTANCED  ----   阻塞

        两个函数的区别:
        a、在一个子进程终止前, wait 使其调用者阻塞,而 waitpid 有一选择项,可使调用
             者不阻塞。
        b、waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的
              进程。
    
    4)、exec系列函数
#include <unistd.h>
extern char **environ;

int execle(const char *pathname, const char *arg, ..., char * const envp[]);
int execve(const char *pathname, char *const argv[], char *const envp[]);


int execl(const char *pathname, const char *arg, ...);
int execv(const char *pathname, char *const argv[]);


int execlp(const char *pathname, const char *arg, ...);
int execvp(const char *pathname, char *const argv[]);


返回:
成功:不返回
失败:-1
参数:
    pathname:需要执行程序的地址
    arg:参数指针
    argv:参数指针数组      
                    ---这里的参数即是传递给新程序main的argv参数
    envp:环境表

在这里插入图片描述

此图可直观的反应六个函数的关系。
从垂直角度来看:"execl"类函数与"execv"类函数的区别在于第二个参数,l表示表(list,一系列
                            参数,但均以NULL结尾),v表示矢量(vector, 参数在指针数组中)
从纵向角度来看:execvp可使用相对路径(但必须是PATH中有的地址)-->execv只能使用绝
                           对路径 --> execve多了一个环境表environ且只能使用绝对路径

exec函数的作用:将子进程完全替换为新的程序,用于实现子进程执行另一个程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值