08.进程控制

1.进程标识

  • 进程ID是唯一的,但也是可复用的,大部分系统采用延迟复用算法
  • ID为0的通常是调度进程,常被称为交换进程,是内核的一部分,不执行磁盘上的程序(所以也叫系统进程)
  • 进程ID为1的通常是init进程,自举过程由内核调用,超级用户特权运行,但是普通的用户进程,不会终止
#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);

2、fork()函数

#include <unistd.h>
pid_t fork(void);
  • 子进程返回0
  • 父进程返回子进程的进程ID
  • fork之后经常跟exec,所以采用了写时复制技术
  • 文件共享:
    • 打开的文件描述符的复制类似于执行了dup()
    • 父子进程共享同一文件偏移量
  • 父子进程的区别:
    • 子进程不继承文件锁
    • 子进程未处理的闹钟被清除
    • 子进程的未处理信号集设置为空集

3、vfork()

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

可移植的程序不应该使用这个函数

  • vfork()创建的子进程并不会完全复制父进程的地址空间,因为会马山调用exec
  • 子进程在调用exec()前在父进程空间中运行
  • vfork保证子进程先运行,子进程调用exec或exit后父进程才恢复运行

4、exit()

  • 进程有5中正常终止的方法:

    • main()中return
    • exit()
    • _[eE]xit
    • 最后一个线程执行return
    • 最后一个线程调用pthread_exit()
  • 进程的3中异常终止状态

    • 调用abort()
    • 接收到某些信号
    • 最后一个线程对"取消"作出响应
  • 父进程在子进程前终止,子进程编程僵尸进程

  • 子进程在父进程前终止,内核为子进程保存一定量的信息(包括进程ID,终止状态,CPU使用时间等)


5、wait()和waitpid()

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
  • 进程终止时向父进程发送SIGCHLD信号
  • 调用wait时:
    • 子进程还活着则阻塞
    • 以终止则立即返回
    • 没有任何子进程则出错返回
  • 返回值指示退出状态、信号编号、是否产生core文件等
    WIFEXITED(status)
    WEXITSTATUS(status)
    WIFSIGNALED(status)
    WTERMSIG(status)
    WCOREDUMP(status)
    WIFSTOPPED(status)
    WSTOPSIG(status)
    WIFCONTINUED(status)
    

6、waitid()

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
  • idtype
    • P_PID:等待特定进程
    • P_PGID:等待特定进程组中的任一子进程
    • P_ALL:等待任一子进程
  • options
    • WCONTINUED:等待一个进程,它以前曾被停止,此后又继续,但状态尚未报告
    • WEXITED:等待已退出的进程
    • WNOHANG:非阻塞
    • WNOWAIT:不破坏子进程的退出状态
    • WSTOPPED:进程已经停止,但状态尚未报告

7、wait3()和wait4()

#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>

pid_t wait3(int *status, int options,
            struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options,
            struct rusage *rusage);
  • 允许内核返回由终止进程及其所有子进程使用的资源概况

8、竞争条件

多个进程企图对共享数据进行处理,结果取决于进程运行顺序

  • 为了避免竞争条件和轮询,进程间需要某种形式信号的发送和接收方法

9、exec()函数

#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
            ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
            char *const envp[]);
  • 进程调用exec函数时,进程执行的程序完全替换为新进程
  • 进程ID不变,因为只是用磁盘上的新程序替换了当前进程的正文段、数据段、堆栈
  • …(暂时用不到就不看了)

10、更改用户ID和更改组ID

int setuid(uid_t uid);
int setgid(gid_t gid);
  • 在linux中,特权以及访问控制是基于用户ID和组ID的
  • 更改用户ID规则
    • 若进程有root权限,实际/有效/保存的设置用户ID设置为uid
    • 。。。

11、解释器文件

  • 起始行是:
    #! pathname [optional-argument]
    

12、system()函数

int system(const char *command);
  • command为空时,可用时返回非0值
  • 返回值
    • -1:fork失败或waitpid返回EINTR之外的值
    • 127?:exec失败
    • shell的终止状态:成功

13、进程会计

启动进程会计后,每当进程结束内核就写一个会计记录:包括命令名、CPU时间总量、用户ID、组ID、启动时间内等

int acct(const char *filename);
  • 该函数用以启用和禁用进程会计,但至今没有一个标准做了声明,只有accton命令用了这个函数

14、用户标识

任一进程都可以得到实际用户ID和有效用户ID及组ID

#include <unistd.h>
char *getlogin(void);
int getlogin_r(char *buf, size_t bufsize);
#include <stdio.h>
char *cuserid(char *string);
  • 用以获取登录名

15、进程调度


16、进程时间

©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页