Chinaunix首页 | 论坛 | 博客
  • 博客访问: 655027
  • 博文数量: 171
  • 博客积分: 2246
  • 博客等级: 大尉
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-31 11:45
文章分类

全部博文(171)

文章存档

2018年(3)

2017年(4)

2015年(1)

2014年(20)

2013年(57)

2012年(86)

分类: LINUX

2013-11-08 15:44:34

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

Linux 上创建线程一般使用的是 pthread 库  实际上 libc 也给我们提供了创建线程的函数 ,那就是 clone
  1. int clone(   int (*fn)(void *),
  2.              void *child_stack,
  3.              int flags,
  4.              void *arg, ...
  5.               /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */
  6.         );
man 手册里面说的很清楚这个函数存在的意义就是实现线程  当然这个函数不是 linux 的系统调用而是对系统调用的封装 。

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

  1. void *pstack = (void *)mmap(    NULL,
  2.                                 STACK_SIZE,
  3.                                 PROT_READ | PROT_WRITE ,
  4.                                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON ,//| MAP_GROWSDOWN ,
  5.                                 -1,
  6.                                 0
  7.                             );

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

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

然后调用 clone 函数

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

几个标识的意义

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.)

下面是我测试的代码

  1. #define _GNU_SOURCE       /* or _BSD_SOURCE or _SVID_SOURCE */
  2. #include <unistd.h>
  3. #include <sys/syscall.h> /* For SYS_xxx definitions */
  4. #include <sys/types.h>
  5. #include <sched.h>
  6. #include <sys/mman.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <sys/wait.h>

  12. #define STACK_SIZE 1024*1024*8 //8M

  13. int thread_func(void *lparam)
  14. {
  15.     printf("thread id %d \n", (int)syscall(SYS_gettid));
  16.     printf("thread get param : %d \n", (int)lparam);
  17.     sleep(1);
  18.     return 0;
  19. }


  20. void child_handler(int sig)
  21. {
  22.     printf("I got a SIGCHLD\n");
  23. }

  24. int main(int argc, char **argv)
  25. {
  26.     setvbuf(stdout, NULL, _IONBF, 0);
  27.     signal(SIGCHLD, child_handler);
  28.     //signal(SIGUSR1, SIG_IGN);

  29.     void *pstack = (void *)mmap(NULL,
  30.                                 STACK_SIZE,
  31.                                 PROT_READ | PROT_WRITE ,
  32.                               MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON ,//| MAP_GROWSDOWN ,
  33.                                 -1,
  34.                                 0);
  35.     if (MAP_FAILED != pstack)
  36.     {
  37.         int ret;
  38.         printf("strace addr : 0x%X\n", (int)pstack);
  39.         /*
  40.         CLONE_VM (0x100) - tells the kernel to let the original process and
  41.                             the clone in the same memory space;
  42.         CLONE_FS (0x200) - both get the same file system information;
  43.         CLONE_FILES (0x400) - share file descriptors;
  44.         CLONE_SIGHAND (0x800) - both processes share the same signal handlers;
  45.         CLONE_THREAD (0x10000) - this tells the kernel, that both processes would belong
  46.                          to the same thread group (be threads within the same process);
  47.         */
  48.         ret = clone(thread_func,
  49.                     (void *)((unsigned char *)pstack + STACK_SIZE),
  50.                     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |SIGCHLD,
  51.                     (void *)NULL);
  52.         if (-1 != ret)
  53.         {
  54.             pid_t pid = 0;
  55.             printf("start thread %d \n", ret);
  56.             sleep(5);
  57.             pid = waitpid(-1, NULL, __WCLONE | __WALL);
  58.             printf("child : %d exit %s\n", pid,strerror(errno));
  59.         }
  60.         else
  61.         {
  62.             printf("clone failed %s\n", strerror(errno) );
  63.         }
  64.     }
  65.     else
  66.     {
  67.         printf("mmap() failed %s\n", strerror(errno));
  68.     }
  69.     return 0;
  70. }

来源: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 置起此标志在进程间共享信号处理程序


阅读(2241) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~