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 ,这个函数常用来完成文件映射 ,这里分配内存也是可以的
通过指定 MAP_ANONYMOUS 标识 系统就不会创建文件映射 而仅仅分配内存
注意堆栈不要太小了 不然会溢出的。。。。。。
然后调用 clone 函数
几个标识的意义
在线程函数中直接 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.)
下面是我测试的代码
来源: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功能相似的系统调用有fork,但fork事实上只是clone的功能的一部分,clone与fork的主要区别在于传递了几个参数,而当中最重要的参数就是conle_flags,下表是系统定义的几个clone_flags标志:
标志 Value 含义
CLONE_VM 0x00000100 置起此标志在进程间共享地址空间
CLONE_FS 0x00000200 置起此标志在进程间共享文件系统信息
CLONE_FILES 0x00000400 置起此标志在进程间共享打开的文件
CLONE_SIGHAND 0x00000800 置起此标志在进程间共享信号处理程序
接着上文没介绍完的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) |
使用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 置起此标志在进程间共享信号处理程序
相关文章推荐
- jquery的clone方法应用于textarea和select的bug修复
- Javascript对象Clone实例分析
- Java利用序列化实现对象深度clone的方法
- ubuntu下会话克隆
- windows image/vhd 相关
- vm 克隆linux系统后,网卡无法正常工作
- VM虚拟机克隆linux后网卡无法启动解决办法
- Vmware克隆Centos 6.4后 重新设置eth0
- Java - 复制ArrayList
- C#浅复制和深复制
- JAVA笔记【20131213】
- 关于java对象复制(clone)
- vmware clone后,修改的地方
- Cloneable
- git 克隆,提交
- OpenCV笔记(copyto,clone)
- linux下的 fork vfork和clone函数
- Java之deep copy(深复制)
- 克隆ORACLE 11G HOME
- Java Object类