Linux 进程,线程和调度 ---- 02

本文详细介绍了Linux中进程的创建方式,包括fork、vfork和clone的区别,深入探讨了写时拷贝(Copy On Write)机制。此外,还讨论了孤儿进程的SUBREAPER机制、进程的睡眠与等待队列以及进程0和进程1的角色和特点。
摘要由CSDN通过智能技术生成

1. fork、 vfork、 clone

写时拷贝技术

在这里插入图片描述
从图中可以看出,在最开始阶段的时候,就是有一个进程在运行,并且虚拟地址是可读可写的

使用fork以后产生了子进程,子进程会拷贝父进程的信息,并且共享内存资源的信息,并把相应的共享虚拟地址标记为只读的状态。

任一一个进程 write 后,写进程会申请新的物理地址,并把共享的物理地址断开,并标记为 R+W,也就是 Copy On Write (COW)机制

这是的 P1 和 P2 的虚拟地址是一样的,就是物理地址不一样

fork 以后的资源形式:

fork():

1. SIGCHLD

在这里插入图片描述

最难分裂的是内存资源,内存资源分配需要 MMU

vfork

在没有 MMU 的 Linux 系统中没有 fork ,只有使用 vfork

没有 Copy On Write, 没有 fork

使用 vfork : 父进程阻塞知道子进程 exit 或者 exec

vfork():

1. CLONE_VM
2. CLONE_VFORK
3. SIGCHLD

在这里插入图片描述

fork 和 vfork 的不同:

在这里插入图片描述

#include <stdio.h>
#include <sched.h>
#include <unistd.h>

int data = 10;

int child_process()
{
   
        printf("Child process %d, data %d\n",getpid(),data);
        data = 20;
        printf("Child process %d, data %d\n",getpid(),data);
        _exit(0);
}

int main(int argc, char* argv[])
{
   
        if(vfork() == 0) {
   
                child_process();
        } else {
   
                sleep(1);
                printf("Parent process %d, data %d\n",getpid(), data);
        }
}

Clone

pthread_create -> clone 通过 clone_flags 传参,共享资源,可以调度的

1. CLONE_VM
2. CLONE_FS
3. CLONE_FILES
4. CLONE_SIGHAND
5. CLONE_THREAD

线程也是 LWP 轻量级进程

clone 就是创建新的 task_struct 结构体

在这里插入图片描述
线程的 PID, POSIX 标准统一个进程穿件的线程使用同一个 PID,在内核里增加了一个 tgid (thread group ID)

在这里插入图片描述

// 编译 gcc thread.c -pthread, 用 strace ./a.out 跟踪其对 clone() 的调用
// ls /proc/$pid/task/  查看 线程ID
// gettid 可以通过系统调用得到 线程ID
// pthread_self 只是拿到用户态的一个编号
#include <stdio.h>
#include <pthread.h>
#include <stdio.h>
#include <linux/unistd.h>
#include <sys/syscall.h>

static pid_t gettid( void )
{
        return syscall(__NR_gettid);
}

static void *thread_fun(void *param)
{
        printf("thread pid:%d, tid:%d pthread_self:%lu\n", getpid(),   gettid(), pthread_self());
        while(1);
        return NULL;
}

int main(void)
{
        pthread_t tid1, tid2;
        int ret;

        printf("thread pid:%d, tid:%d pthread_self:%lu\n", getpid(), gettid(),pthread_self());

        ret = pthread_create(&tid1, NULL, thread_fun, NULL);
        if (ret == -1) {
                perror("cannot create new thread");
                return -1;
        }

        ret = pthread_create(&tid2, NULL, thread_fun, NULL);
        if (ret == -1) {
                perror("cannot create new thread");
                return -1;
        }

        if (pthread_join(tid1, NULL) != 0) {
                perror("call pthread_join function fail");
                return -1;
        }

        if (pthread_join(tid2, NULL) != 0) {
                perror("call pthread_join function fail");
                return -1;
        }

        return 0;
}

2. 孤儿进程的托孤, SUBREAPER

在新的系统中不仅可以托孤给 init,也可以托孤给一个 subreaper 的进程

在这里插入图片描述

subreaper 进程要做一些事情

/* Become reaper of our children */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
   
    log_warning("Failed to make us a subreaper: %m");
    if (errno == EINVAL)
        log_info("Perhaps the kernel version is too old (<3.4?)");
}

PR_SET_CHILD_SUBREAPER 是 Linux 3.4 加入的新特性。把它设置为
非零值,当前进程就会变成 subreaper,会像 1 号进程那样收养孤儿进程

life-period例子,实验体会托孤

// 编译运行 life_period.c,杀死父进程,用 pstree 命令观察子进程的被托孤
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
   
	pid_t pid,wait_pid;
	int status;

	pid = fork();

	if (pid==-1)	{
   
		perror("Cannot create new process");
		exit(
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值