linux下使用clone创建进程

一、clone函数

1.1、函数原型

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

头文件:

#define _GNU_SOURCE
#include <sched.h>

函数作用:clone函数允许用户指定子进程继承或者拷贝父进程的某些特定资源,如信号量、文件描述符、文件系统、内存等内容。

函数参数:

1)fn 新创建进程的入口函数;

2)clid_stack 子进程栈空间的起始地址;

3)arg 传递给子进程的参数,需要和CLONE_SETTLS一起使用

4)ptid 存储父进程的pid,需要和CLONE_PARENT_SETTID一起使用

5)tls (Thread Local Storage) descriptor,需要和CLONE_SETTLS一起使用

6)ctid 存储子进程的pid,需要和CLONE_CHILD_SETTID选项一起使用

3)flag 创建进程的属性

返回值:

成功返回子进程的ID号,失败返回-1.

1.2、flag各参数的含义和用法,这里只介绍了部分参数的含义,其它参数的含义请参考clone(2)

  • CLONE_FILES
    父进程和子进程共享相同的文件描述符表,例如在父进程中创建或者改变了某个文件描述符,也会影响子进程中该文件描述符,反过来也成立;如果这个选项没有被打开,那么子进程只会继承父进程中文件描述符的拷贝,父进程中对相应文件描述符的改变不影响子进程,反之也成立;
  • CLONE_FS
    子进程和父进程共享相同的文件系统信息,包含根文件系统、当前工作目录、unmask。
  • CLONE_IO
    父子进程共享相同的IO环境;
  • CLONE_NEWIPC
  • CLONE_NEWNET
  • CLONE_NEWNS
  • CLONE_NEWPID
  • CLONE_NEWUTS
  • CLONE_PARENT
    这个选项表示新创建的子进程的父进程不是调用者,而是调用者的父进程,新的子进程和它的调用者拥有相同的父进程;
  • CLONE_PARENT_SETTID

    存储父进程的pid到clone函数的ptid中;
  • CLONE_PID(Linux 2.0 to 2.5.15)

    Linux 2.5.16之后该选项被弃用;
  • CLONE_PTRACE
    若父进程被trace,子进程也会被trace。
  • CLONE_SETTLS
  • CLONE_SIGHAND
    子进程和父进程共享相同的table of signal handlers。
  • CLONE_STOPPED
    这个选项原意是在创建子进程时将子进程停止运行,类似于子进程接收到了SIGSTOP,在收到SIGCONT信号后重新恢复;
    这个选项在linx2.6.25版本中被弃用,在2.6.38版本中被移除,从linux4.6开始这个位被CLONE_NEWCGROUP替代;
  • CLONE_SYSVSEM(linux2.5.10以后)
    父进程和子进程共享相同的信号量;
  • CLONE_THREAD
  • CLONE_UNTRACED
  • CLONE_VFORK

    父进程会一直挂起直到子进程结束,使用这个选项的作用和vfork类似;
  • CLONE_VM
    这个选项可以使父进程和子进程运行在相同的内存中,如果没有设置这个选项,子进程和父进程运行在不同的内存空间。

二、clone和fork的区别

1)clone允许新创建的进程共享调用它的进程(通常是父进程)的部分资源,比如内存空间、文件描述符表、信号量等,具体需要共享那些内容可以通过clone的flag参数设置;

2)fork函数创建的子进程可以看做是父进程的完全拷贝,而clone则是有选择性的拷贝;

三、示例代码:

#define _GNU_SOURCE //注意,这个宏必须在最前面,否则编译会报错
#include <sched.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/select.h>
#include <stdlib.h>

int value = 0;

int child_progress(void *arg)
{
	while(1)
	{
		printf("child,value = %d\r\n",value);
		value ++;
		sleep(1);
		if(value == 5)break;
	}
	return 0;
}
void main(int argc,char *argv[])
{
	int ret = -1;
	char *stack = NULL;
    pid_t tid = 0;

    stack = malloc(4096);
	if(NULL == stack)
	{
		printf("malloc fail]\r\n");
		return;
	}
	//子进程继承父进程的数据空间/在子进程结束后运行/将子进程的id存储到tid变量中
    int mask = CLONE_VM|CLONE_VFORK|CLONE_CHILD_SETTID;
	
	ret = clone(child_progress,stack+4096,mask,NULL,NULL,NULL,&tid);//栈地址向下增长,因此起始地址为stack+4096
	if(ret < 0)
	{
		printf("clone error\r\n");
		return;
	}
	printf("clone sucess,pid:%d %d\r\n",ret,tid);
    while(1)
	{
		printf("father,value = %d\r\n",value);
		value ++;
		sleep(1);
	}
}

运行结果:

在这里插入图片描述

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值