Linux 进程创建一(system和fork)
一:system系统调用
#include <stdlib.h>
int system(const char *string);
system函数传递给/bin/sh -c 来执行string所指定的命令。
string中可以包含选项和参数
如果没有找到/bin/sh。函数返回127,如果出现其他错误返回-,成功返回0,但如果string为NULL,返回一个非0值
system调用其他进程是通过shell调用其他进程,本程序进程与被调用的进程之间没有关系。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h> int main(int arg, char * args[])
{
system("ls -l");
return ;
}
二:fork系统调用
#include<unistd.h>
pid_t fork(void);
fork执行成功,向父进程返回子进程的PID,并向子进程返回0,这意味着fork即使只调用一次,也会返回两次。
fork创建的新进程是和父进程(除了PID和PPID)一样的副本。
父进程和子进程之间有点区别,子进程没有继承父进程的超时设置(使用alarm调用)、父进程创建的文件锁,或者未决信号。
但是子进程会继承父进程的文件描述符,内存空间大小,代码
你不能预计父进程是在他的子进程之前还是之后运行,他的执行是无序的,是异步的。
fork的异步行为意味着你不应该在子进程中执行依赖与父进程的代码,反之亦然。
fork调用可能失败,原因是系统上已经运行了太多进程,已经超过了允许他执行的最大进程数。
fork执行失败,会向父进程返回-,而且不创建子进程,更新errno。
fork执行成功,向父进程返回子进程的PID,向子进程返回0。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h> int main(int arg, char * args[])
{
pid_t child=fork();
if(child==-)
{
printf("操作系统出错!\n");
return -;
}
if(child==)
{
//此时在子进程中
printf("child is begining!\n");
sleep();
printf("child is end!\n");
}else
{
//此时在父进程中,child大于零,child的值就是子进程的PID
printf("parent is begining!\n");
sleep();
printf("parent is end!\n");
}
/*
通过观察"/proc"下的父子进程,发现父子进程共用一段代码
*/
return ;
}
当进程执行到fork()函数的时候,会复制自身,创建一个新进程,父进程,子进程都会执行fork()函数,
子进程的代码执行将会从fork()函数开始,而不是重新将所有父进程代码执行一遍(因为这样会出现重复执行fork函数,不断的创建新进程)
fork系统调用的特殊之处在于一段代码在不同的两个进程中运行(例如if的两个分支)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h> int main(int arg, char * args[])
{
int i=;
for(;i<;i++)
{
pid_t child=fork();
}
/*
这样会创建4个进程,分别是2个父进程,2个子进程
这其实很像一棵树
父进程A执行第一次循环,生成子进程B,此时父进程A中child=子进程B的PID;子进程B的child=0
当父进程执行第二次循环,生成子进程C,此时父进程A中child=子进程C的PID;子进程C的child=0
但是此时子进程B会执行fork()函数之后的代码,所以子进程B会再次执行一次fork()函数,
此时系统会复制子进程B成为一个新的孙子进程D,那么子进程B就会变成一个父进程。
*/
return ;
}
//fork函数共享文件标识符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main(int arg, char * args[])
{
if(arg<)
{
printf("请输入一个参数!\n");
return -;
}
int fd=open(args[],O_WRONLY);
if(fd==-)
{
printf("error msg:%s\n",strerror(errno));
return -;
}
//create new process
pid_t child=fork();
if(child==)
{
sleep();
printf("child is beining\n");
//child process
//write the file
char buf[]={};
int index=;
strcpy(buf,"fly on air!\n");
index=write(fd,buf,strlen(buf)+);
printf("write count :%d\n",index);
//close the file
/*
对close()函数加强
close()关闭是对文件标识符的引用减一,直到对文件标识符的引用变成0,该文件才会真正关闭
当执行fork()函数后对文件标识符fd引用就变成两个,
fd同时被父进程和子进程所引用
所以单独在父进程或者子进程中close()并无法关闭文件引用
必须同时在父进程和子进程关闭引用
*/
close(fd);
printf("child is end\n");
}else
{
printf("parent beining\n");
close(fd);
printf("parent is end\n");
/*
函数名: exit()
所在头文件:stdlib.h(如果是”VC6.0“的话头文件为:windows.h)
功 能: 关闭所有文件,终止正在执行的进程。
exit(0)表示正常退出,
exit(x)(x不为0)都表示异常退出,这个x是返回给操作系统(包括UNIX,Linux,和MS DOS)的,以供其他程序使用。
*/
exit();
//程序exit(0)后面的代码都不会执行,此时进程已经退出
printf("l am not protect!\n");
}
printf("all end!\n");
return ;
}

详解:程序在fork()函数之前open()打开一个文件描述符fd3,这个文件描述符指向一个文件表A(fd3类似于一个指针,指向一个文件表的内存区域),
执行fork()函数后,当子进程中使用了文件描述符fd3时,那么Linux内核会写时拷贝fd3文件描述符到子进程中,此时子进程中的fd3文件描述符也指向
同一个文件表A(类似于两个指针指向同一片内存),此时Linux内核会将refcnt这个值加1,表示现在有2个进程引用该文件描述符所以关闭该文件表,
需要在父进程和子进程中分别关闭。
Linux 进程创建一(system和fork)的更多相关文章
- Linux进程创建和结束
在Linux中,进程的创建由系统调用fork和vfork完成.它们生成一个子进程并且子进程是父进程的一个复制品. Fork系统调用对应的kernel函数是sys_fork,此函数简单的调用kernel ...
- Linux 进程创建二(execve和wait)
三:execve系统调用 int execve(const char *filename, char *const argv[],char *const envp[]); fork创建了一个新的进程, ...
- linux 进程创建clone、fork与vfork
目录: 1.clone.fork与vfork介绍 2.fork说明 3.vfork说明 4.clone说明5.fork,vfork,clone的区别 内容: 1.clone.fork与vfork介绍 ...
- Linux进程通信之System V消息队列
System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...
- linux进程创建
1. 进程是程序的执行,会被加载到内存中,每个进程包括程序的代码和数据,其中数据包括程序的变量的数据,外部数据,程序堆栈. 2. Linux中,输入命令,如vi main.c 通过shell来执行, ...
- Linux进程通信之System V共享内存
前面已经介绍过了POSIX共享内存区,System V共享内存区在概念上类似POSIX共享内存区,POSIX共享内存区的使用是调用shm_open创建共享内存区后调用mmap进行内存区的映射,而Sys ...
- linux进程间通讯-System V IPC 信号量
进程间通信的机制--信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的很多其它内容,能够阅读我的还有一篇文章:Linux进程间通信--使用信号.以下就进入信号量的 ...
- 二十六、Linux 进程与信号---system 函数 和进程状态切换
26.1 system 函数 26.1.1 函数说明 system(执行shell 命令)相关函数 fork,execve,waitpid,popen #include <stdlib.h> ...
- Linux学习--进程创建
进程创建 在Linux系统下,自己可以创建进程: 当进程执行时,它会被装载进虚拟内存,为程序变量分配空间,并把相关信息添到 task_struct里. 进程内存布局分为四个不同的段: • 文本段,包含 ...
随机推荐
- debian6 安装VirtualBox的方法
方法一: 参考: https://www.virtualbox.org/wiki/Linux_Downloads 更新sources.list deb http://download.virtu ...
- 【docker】查看docker镜像的版本号TAG,从远程仓库拉取自己想要版本的镜像
要想查看镜像的版本好TAG,需要在docker hub查看 地址如下:https://hub.docker.com/r/library/ 进入之后,在页面左上角搜索框搜索, 例如搜索redis 搜索完 ...
- Android线程与线程池
引言 在Android中,几乎完全采用了Java中的线程机制.线程是最小的调度单位,在很多情况下为了使APP更加流程地运行,我们不可能将很多事情都放在主线程上执行,这样会造成严重卡顿(ANR),那么这 ...
- WebLogic Server 多租户资源迁移
重新建立一个动态集群,并启动,注意监听地址不能和其他集群重合 选择相应的资源组进行迁移, 迁移后,访问新的地址成功. 通过OTD负载均衡器访问原有的地址成功. 直接访问原来后台地址失败,表示资源确实已 ...
- 设置html属性为disabled时flask后台获取数据失败
标签input的值如果不需要用户修改,则设置属性为 readonly,不要设置为 disabled.因为设置disabled会导致flask后端获取不到这个input得value rule_maker ...
- grpc(3):使用 golang 开发 grpc 服务端和client
1,关于grpc-go golang 能够能够做grpc的服务端和client. 官网的文档: http://www.grpc.io/docs/quickstart/go.html https://g ...
- 蓝鲸安装Agent
1. APPO 所在机器(在 app 运行所在机器) 必须能通过 ssh 登陆到 Agent 机器2. Agent 所在机器可以访问到 zk 的端口3. 支持 Linux/Windows/AIX 操作 ...
- uva 11584 Partitioning by Palindromes 线性dp
// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串 ...
- ngrinder安装
1.源码编译和部署 官网:http://naver.github.io/ngrinder/ 下载源码后,存在部分依赖库不在maven的远程仓库中,这是可以用下载jar包后,用以下命令打包到本地仓库: ...
- Python 的基本运算和内置函数
一.运算符 (一)Python算术运算符 以下假设变量: a=10,b=20: 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 a ...