Linux 中使用 clone 函数

本文详细介绍了Linux内核中clone函数的原理与使用方法,阐述了如何通过clone函数创建线程,包括创建线程所需的关键步骤、参数解释及其在不同场景下的应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:http://my.oschina.net/sincoder/blog/132303

接着上文没介绍完的clone的细节。

Linux 上创建线程一般使用的是 pthread 库  实际上 libc 也给我们提供了创建线程的函数 ,那就是 clone

int clone(   int (*fn)(void *), 
             void *child_stack,
             int flags, 
             void *arg, ...
              /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */
        );
man 手册里面说的很清楚这个函数存在的意义就是实现线程  当然这个函数不是 linux 的系统调用而是对系统调用的封装 。

首先需要给新的线程创建个堆栈 ,使用函数 mmap ,这个函数常用来完成文件映射 ,这里分配内存也是可以的

  1. void *pstack = (void *)mmap(    NULL,
                                    STACK_SIZE,
                                    PROT_READ | PROT_WRITE ,
                                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON ,//| MAP_GROWSDOWN ,
                                    -1,
                                    0
                                );

    通过指定  MAP_ANONYMOUS 标识  系统就不会创建文件映射 而仅仅分配内存

    注意堆栈不要太小了  不然会溢出的。。。。。。

    然后调用 clone 函数

    ret = clone(   thread_func,
                   (void *)((unsigned char *)pstack + STACK_SIZE),
                   CLONE_VM | CLONE_FS | CLONE_THREAD | CLONE_FILES | CLONE_SIGHAND | SIGCHLD,
                   (void *)NULL
                );
    注意堆栈是向下增长的  所以指定对战的内存的时候 要使用分配内存的尾部的指针

    几个标识的意义

    flags
    value        
    discription
    CLONE_VM
    (0x100)
    tells the kernel to let the original process and the clone in the same memory space;
    CLONE_FS
    (0x200)
    both get the same file system information
    CLONE_FILES
    (0x400)
    share file descriptors
    CLONE_SIGHAND
    (0x800)
    both processes share the same signal handlers;
    CLONE_THREAD
    (0x10000)
    this tells the kernel, that both processes would belong to the same thread group (be threads within the same process)

    在线程函数中直接 return 就可以退出线程了。。。。

      使用clone 的时候 指定 CLONE_THREAD 那么以后就不能使用 wait 来等待这个线程了相当于 deteched .了。。。查看man 手册可以看到

    A new thread created with CLONE_THREAD has the same parent process as the caller of clone() (i.e., like CLONE_PARENT), so that calls  to getppid(2)  return the same value for all of the threads in a thread group.  When a CLONE_THREAD thread terminates, the thread that created it using clone() is not sent a SIGCHLD (or other termination) signal; nor can the  status  of  such  a  thread  be  obtained  using wait(2).  (The thread is said to be detached.)

    下面是我测试的代码

    #define _GNU_SOURCE       /* or _BSD_SOURCE or _SVID_SOURCE */
    #include <unistd.h>
    #include <sys/syscall.h> /* For SYS_xxx definitions */
    #include <sys/types.h>
    #include <sched.h>
    #include <sys/mman.h>
    #include <signal.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/wait.h>
    
    #define STACK_SIZE 1024*1024*8 //8M
    
    int thread_func(void *lparam)
    {
        printf("thread id %d \n", (int)syscall(SYS_gettid));
        printf("thread get param : %d \n", (int)lparam);
        sleep(1);
        return 0;
    }
    
    
    void child_handler(int sig)
    {
        printf("I got a SIGCHLD\n");
    }
    
    int main(int argc, char **argv)
    {
        setvbuf(stdout, NULL, _IONBF, 0); 
        signal(SIGCHLD, child_handler);
        //signal(SIGUSR1, SIG_IGN);
    
        void *pstack = (void *)mmap(NULL,
                                    STACK_SIZE,PROT_READ | PROT_WRITE ,
                                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON ,//| MAP_GROWSDOWN ,
                                    -1,
                                    0);
        if (MAP_FAILED != pstack)
        {
            int ret;
            printf("strace addr : 0x%X\n", (int)pstack);
            /*
            CLONE_VM (0x100) - tells the kernel to let the original process and 
                                the clone in the same memory space;
            CLONE_FS (0x200) - both get the same file system information;
            CLONE_FILES (0x400) - share file descriptors;
            CLONE_SIGHAND (0x800) - both processes share the same signal handlers;
            CLONE_THREAD (0x10000) - this tells the kernel, that both processes would belong
                             to the same thread group (be threads within the same process);
            */
            ret = clone(thread_func,
                        (void *)((unsigned char *)pstack + STACK_SIZE),
                        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |SIGCHLD,
                        (void *)NULL);
            if (-1 != ret)
            {
                pid_t pid = 0;
                printf("start thread %d \n", ret);
                sleep(5);
                pid = waitpid(-1, NULL, __WCLONE | __WALL);
                printf("child : %d exit %s\n", pid,strerror(errno));
            }
            else
            {
                printf("clone failed %s\n", strerror(errno) );
            }
        }
        else{
            printf("mmap() failed %s\n", strerror(errno));
        }
        return 0;
    }

    来源:http://www.cnblogs.com/wanghetao/archive/2011/11/06/2237931.html
    int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);

    这里fn是函数指针,我们知道进程的4要素,这个就是指向程序的指针,就是所谓的“剧本", child_stack明显是为子进程分配系统堆栈空间(在linux下系统堆栈空间是2页面,就是8K的内存,其中在这块内存中,低地址上放入了值,这 个值就是进程控制块task_struct的值),flags就是标志用来描述你需要从父进程继承那些资源, arg就是传给子进程的参数)。下面是flags可以取的值

    标志                     
    含义
     CLONE_PARENT 

     创建子进程的父进程是调用者的父进程新进程与创建它的进程成了“兄弟”而不是“父子”

    CLONE_FS

    子进程与父进程共享相同的文件系统,包括root、当前目录、umask

     CLONE_FILES

     子进程与父进程共享相同的文件描述符(file descriptor)表

    CLONE_NEWNS
    在新的namespace启动子进程,namespace描述了进程的文件hierarchy
    CLONE_SIGHAND
    子进程与父进程共享相同的信号处理(signal handler)表
    CLONE_PTRACE
    若父进程被trace,子进程也被trace
    CLONE_VFORK
    父进程被挂起,直至子进程释放虚拟内存资源
    CLONE_VM
    子进程与父进程运行于相同的内存空间
    CLONE_PID
    子进程在创建时PID与父进程一致
     CLONE_THREAD
    Linux 2.4中增加以支持POSIX线程标准,子进程与父进程共享相同的线程群
    下面的例子是创建一个线程(子进程共享了父进程虚存空间,没有自己独立的虚存空间不能称其为进程)。父进程被挂起当子线程释放虚存资源后再继续执行。

    与系统调用clone功能相似的系统调用有fork,但fork事实上只是clone的功能的一部分,clone与fork的主要区别在于传递了几个参数,而当中最重要的参数就是conle_flags,下表是系统定义的几个clone_flags标志:
    标志 Value 含义
    CLONE_VM 0x00000100 置起此标志在进程间共享地址空间
    CLONE_FS 0x00000200 置起此标志在进程间共享文件系统信息
    CLONE_FILES 0x00000400 置起此标志在进程间共享打开的文件
    CLONE_SIGHAND 0x00000800 置起此标志在进程间共享信号处理程序




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值