C++笔记--Linux编程(10)-进程控制 fork系统调用
Posted xiangjai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++笔记--Linux编程(10)-进程控制 fork系统调用相关的知识,希望对你有一定的参考价值。
Linux进程模型
传统的Linux模型里有三种创建或者修改进程的操作
1. system用于调用shell,执行一个指定的命令;
2. fork用于创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;
3. exec可以在进程中用另外的程序来替换当前运行的进程
什么是进程
进程是一个正在执行的程序实例,他也是Linux基本的调度单位,一个进程由如下元素组成
进程的当前上下文(context),它是进程当前执行状态
进程的当前执行目录
进程访问的文件和目录
程序的访问权限
内存和其他分配给进程的系统资源
进程标识号
进程最知名的属性就是进程号(processID,PID)和它父进程号(parent processID,PPID)
PID和PPID都是非零的整数。 一个PID唯一标识一个进程。 一个进程创建的另一个新进程称为子进程。相反地,创建子进程的进程称为父进程。
所有进程追溯其祖先最终都会落到进程号为1的进程身上,这个进程叫init进程 Init进程是linux内核启动后第一个执行的进程。 Init引导系统,启动守护进程并且运行必要的程序。
进程PID和父进程PPID示例
创建多进程示例
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
int main () {
pid_t pid;
printf("start, pid=%d, ppid=%d\\n", getpid(), getppid());
int len = 4;
for(int i=0; i<len; i++) {
pid = fork();
if(pid == 0) {
printf("I am is child pid, pid=%d, ppid=%d\\n", getpid(), getppid());
break;
} else if(pid > 0) {
printf("I am is parent pid, pid=%d, ppid=%d\\n", getpid(), getppid());
}
}
sleep(4);
printf("exit, pid=%d, ppid=%d\\n", getpid(), getppid());
while (1) {
sleep(4);
}
return 0;
}
创建进程
system系统调用
#include <stdlib.h>
int system(const char *string);
system函数传递给/bin/sh –c 来执行string所指定的命令
string中可以包含选项和参数。
如果没有找到/bin/sh,函数返回127,如果出现其他错误返回-1,成功返回0,但如果string为NULL,返回一个非0值
示例
int main(void)
{
printf(“%d\\n”, system(“ls –l”));
return EXIT_SUCCESS;
}
fork系统调用
#include <unistd.h>
pid_t fork(void);
pid_t fork(void); fork执行成功,向父进程返回子进程的PID,并向子进程返回0,这意味着fork即使只调用一次,也会返回两次
fork创建的新进程是和父进程(除了PID和PPID)一样的副本
父进程和子进程之间有点区别,子进程没有继承父进程的超时设置(使用alarm调用)、父进程创建的文件锁,或者未决信号
int main(void)
{
pid_t child = fork();
if(child == -1)
{
printf("call fork error\\n");
return -1;
}
if(child == 0)
{
printf("is child\\n");
}
else
{
printf("child pid is %d\\n", child);
}
return 0;
}
你不能预计父进程是在它的子进程之前还是之后运行,它的执行是无序的,是异步的。
fork的异步行为意味着你不应该在子进程中执行依赖与父进程的代码,反之亦然。
fork调用可能失败,原因是系统上已经运行了太多进程,已经超过了允许它执行的最大进程数。 fork执行失败,会向父进程返回-1,而且不创建子进程。
fork过程包括把父进程全部内存映像复制给子进程,这个过程很缓慢。
UNIX的设计者创建了vfork调用,vfork调用也创建新进程,但它不产生父进程的副本。
Linux已经使用了写时复制技术,因此Linux的fork和UNIX的vfork一样快。
execve函数
int execve(const char *path, const char *arg, char * const envp[]);
fork创建了一个新的进程,产生一个新的PID。
execve用被执行的程序完全替换了调用进程的映像。
execve启动一个新程序,替换原有进程,所以被执行进程的PID不会改变。
execve函数接受三个参数。
path-要执行的文件完整路径;
argv-传递给程序完整参数列表,包括argv[0],它一般是执行程序的名字;
envp-是指向执行execed程序的环境指针,可以设为NULL。
示例
int main(void)
{
char *args[] = { "/bin/ls", "-l", NULL };
execve("/bin/ls", args, NULL);
return 0;
}
wait和waitpid函数
wait和waitpid函数可以收集子进程的退出状态
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
stauts保存子进程的退出状态
pid为等待进程的PID,它能接受下表列出的4种值中的一个
示例
wait函数示例
int main () {
pid_t pid = fork();
if(pid == 0) {
printf("I am is child pid, pid=%d, ppid=%d\\n", getpid(), getppid());
sleep(2);
return 0;
} else if(pid > 0) {
printf("I am is parent pid, pid=%d, ppid=%d\\n", getpid(), getppid());
int status;
pid_t wpid = wait(&status);
printf("wait ok wpid=%d, pid=%d\\n", wpid, pid);
if(WIFEXITED(status)) {
printf("child exit with %d\\n", WEXITSTATUS(status));
} else if(WIFSIGNALED(status)) {
printf("child kill with %d\\n", WTERMSIG(status));
}
}
return 0;
}
以上是关于C++笔记--Linux编程(10)-进程控制 fork系统调用的主要内容,如果未能解决你的问题,请参考以下文章