您的位置:首页 > 运维架构 > Linux

Linux 中使用 clone 函数

2015-08-28 10:38 891 查看
来源: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 ,这个函数常用来完成文件映射 ,这里分配内存也是可以的

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 (
c07b
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 置起此标志在进程间共享信号处理程序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  clone