clone自己实现线程创建

在linux上,进程跟线程在内部实现上其实是一个东西,从 clone系统调用上就可以看出。

fork() 和 pthread_create 都可以 clone 来实现,当当前进程在调用clone时指定了,CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SIGHAND 等共享虚拟内存,共享文件系统相关属性,进程id相同等,那么就是创建线程,如果没有指定,所有大多数东西都不共享,那么就是创建子进程,子进程就会利用写时拷贝技术在需要修改时,创建一个副本。

下面是利用clone系统调用实现线程

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>

#define STACK_SIZE 4096 * 10

static int g_a = 0;

static int thread_func(void *buf)
{
    char *b = (char *)buf;
    printf("[child_pid:%d]receive buf from father is [%s]\n", getpid(), b);

    sleep(5);

    return 0;
}

int main(int argc, char **argv)
{
    int res, status;

    char *addr = mmap(NULL, STACK_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_GROWSDOWN, -1, 0);
    //char *addr = malloc(STACK_SIZE);

    printf("addr:0x%x pid:%d\n", addr, getpid());

    char buf[1024];
    sprintf(buf, "i am father buf");


    int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES
                        | CLONE_THREAD | CLONE_SIGHAND //这两个需要成对出现
                        | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID);

    pid_t ptid, ctid;

    res = clone(thread_func, addr + STACK_SIZE, clone_flags, buf, &ptid, NULL, &ctid);
    if (res == -1) {
        perror("clone");
        return -1;
    }

    //因为我们设置了 CLONE_CHILD_CLEARTID 子进程终止,ctid会清0
    //这里我们简单监控线程终止,实际可以使用 futex 系统调用监控
    //futex 可以参考 http://manpages.ubuntu.com/manpages/bionic/man2/futex.2.html
    while(ctid) {
        printf("ctid:%d\n", ctid);
        sleep(1);
    }

    printf("child done\n");

    if (munmap(addr, STACK_SIZE) == -1) {
        perror("munmap");
        return -1;
    }

    printf("father done\n");
    return 1;

    while(1) {
        g_a++;
        sleep(1);
    }

    return 0;
}


上一篇: linux c 控制台输出控制
下一篇: 无
作者邮箱: 203328517@qq.com