Linux 进程控制

相关概念

  • 程序: 编译好的二进制文件, 存放在磁盘上(占用的是物理内存空间), 不占用系统资源(CPU, 内存, 打开的文件, 设备, 锁...)
  • 进程: 抽象的概念, 与操作系统原理联系紧密, 是活跃的程序, 占用系统资源, 在内存中执行.
    由原来的单道程序设计转换成多道程序设计, 是CPU分成若干的时间碎片, 各个进程抢占资源去执行, 虽然程序有优先级高低, 但是只是抢占到的几率高; 即使是多核, 也是需要时才会开启其他核.
    处理速度:寄存器->cache->内存->硬盘->网络->存储介质
    其他概念: 串行和并发, CPU和MMU
  • 进程控制块 PCB 在/usr/src/linux-headers-3.15.0-30/include/linux/sched.h文件中可以查看struct task_struct 结构体定义, 包含部分定义: 进程id, 进程状态, 进程切换时需要保存和回复的CPU寄存器, 描述虚拟的地址空间信息, 当前工作目录, 文件描述符表, 用户id和组id, 会话和进程组, 资源上限(命令:ulimit -a 查看), umask掩码...
  • 进程状态: 初始态(创建时, 非常短暂), 就绪态(有执行资格, 但是没执行权限, 需要抢占资源), 运行态(正在执行), 挂起态(没有执行资格和执行权限), 终止态
    点我查看进程状态图

进程控制

程序默认的是单进程的; 下面介绍多进程的使用
创建进程函数: pid_t fork(void);(查看 Linux下使用命令:man 2 fork)
点击查看描述图
返回值: 失败返回-1, 父进程返回子进程ID, 子进程返回0
查看当前进程 ps aux | grep "要查找的程序"; ps ajx

Linux 进程控制_第1张图片
父子进程.png

刚fork完成时(父子进程之间) 1. 0-3G地址空间相同 2. PCB相同, 但是pid除外 3.其他内容由mmu映射到物理内存上, 读时共享, 写时复制

获取pid 和 ppid 对应的函数是getpid(); getppid();

//wait 函数回收子进程
#include 
#include 
#include 
int main() {
    pid_t pid;
    pid = fork();
    
    if(pid == -1) {
        perror("fork error");
        exit(-1);
    } else if(pid > 0) {
        printf("parent process\n");
    } else if(pid == 0) {
        printf("child process\n");
    }

    printf("mul process\n");
    return 0;
}

回收进程

进程有孤儿进程, 僵尸进程

  1. 孤儿进程 : 子进程活着, 父进程死了, linxu中的init进程会领养孤儿
  2. 僵尸进程 : 子进程死了, 父进程正在忙, 没有去回收子进程
  3. 进程回收 : 代码附在下边

wait - 阻塞函数
pid_t wait(int* status);
调用一次回收一个子进程资源
返回值:

0: 回收的子进程的pid;
-1: 没有子进程可以回收了;
status -- 传出参数
获取退出时候的返回值

  • 正常退出( return num; exit(num); exit(num);
    )
    WIFEXITED(status) > 0

获取返回值: WEXITSTATUS(status)

  • 被信号杀死
    WIFSIGNALED(status) > 0

获取杀死子进程的信号
WTERMSIG(status)

waitpid -- pid_t waitpid(pid_t pid, int *status, int options);
(可以设置非阻塞, 提高wait的效率)
pid: -1: 所有的子进程
0: 当前进程组的子进程

0(pid): 回收指定进程的pcb
-pid: 回收不在当前进程组的子进程

opttions: 阻塞: 0
非阻塞: WNOHANG 可以设置为非阻塞
可以有针对性的回收某一个子进程资源 ;需要注意的是即使是非阻塞, 也需要循环来回收子进程

//wait函数回收子进程
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int counter = 100;

int main(int argc, const char* argv[])
{
    int number = 5;

    int i;
    pid_t pid;

    for(i=0; i
//验证父子进程是否文件共享
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, const char* argv[]) {
    int fd = open("temp", O_CREAT | O_RDWR, 0664);
    if(fd == -1) {
        perror("open error");
        exit(1);
    }

    pid_t pid = fork();
    if(pid == -1)  {
        perror("fork error");
        exit(1);
    }

    if(pid > 0) {
        char* p = "123123123";
        write(fd, p, strlen(p)+1);
    } else if(pid == 0) {
        // 睡1s保证父进程已经完成了文件的写操作
        sleep(1);
        char buf[1024];
        lseek(fd, 0, SEEK_SET);
        int len = read(fd, buf, sizeof(buf));
        printf("%s\n", buf);
    }
    close(fd);
    return 0;
}
//子进程执行不同任务, 父进程负责回收子进程
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, const char* argv[])
{
    int i = 0;
    int number = 3;
    pid_t pid;

    for(i = 0; i
//waitpid 来回收子进程, 注意非阻塞时也需要循环去回收
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, const char* argv[])
{
    int num = 3;
    int i = 0;
    pid_t pid;

    for(i=0; i

你可能感兴趣的:(Linux 进程控制)