进程的相关函数使用

来源:互联网 发布:微商的发展趋势知乎 编辑:程序博客网 时间:2024/05/17 21:42

上篇我们说到什么是进程,获取进程的id,那么怎么创建一个进程呢,我们可以使用fork函数。

一、fork又叫分叉函数。

将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

二、函数有以下特点:

①当fork()顺利完成任务时,就会存在两个进程,每个进程都从fork()返回处开始继续执行。         
②两个进程执行相同的代码(text)段,但是有各自的堆栈(stack)段、数据(data)段以及堆(heap)。
③子进程的stack、data、heap segments是从父进程拷贝过来的。
④fork()之后,哪一个进程先执行(scheduled to use the CPU)不确定。

三、函数原型:(我们同样可以使用man一下)


pid_t fork( void);
(pid_t 是一个宏定义, 被定义在#include<sys/types.h>中)
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1

四、fork有三个返回值 。由fork创建的进程称为子进程,原来的是父进程。两次返回的唯一区别是子进程中返回0值,而父进程中返回子进程ID。

#include <sys/types.h>#include <unistd.h>#include <stdio.h>int main(){// fork : 创建一个子进程// 如果创建失败 返回 -1// 成功返回两个值,如果是在父进程中,返回子进程的ID// 如果是在子进程,返回值是0pid_t pid = fork();if (pid == -1){perror ("fork");return -1;}if (pid > 0)         // 父进程{printf ("我是父进程,pid = %d\n", getpid());}else if (pid == 0)   // 子进程{printf ("我是子进程,pid = %d\n", getpid());}while (1);return 0;}
我们可以这样理解fork函数返回的值为什么在父子进程中不同。其实就相当于链表,进程形成了链表,父进程的fork函数返回的值指向子进程的进程id, 因为子进程没有子进程,所以其fork函数返回的值为0.

调用fork之后,数据、堆、栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。
fork函数的理解:
#include <sys/types.h>#include <unistd.h>#include <stdio.h>int count = 0;int main(){// int count = 0;pid_t pid = fork();count++;printf ("count = %d\n", count);return 0;}

程序中,因为fork会复制两个栈堆数据,所以count的值都是为0,count++;分别在两个进程各加一次,均为1..
更加深刻的理解一下fork:
#include <sys/types.h>#include <unistd.h>#include <stdio.h>int main(){fork();fork() && fork() || fork();fork();printf("a\n");while (1);return 0;}
第一个fork和最后一个fork肯定是会执行的。
主要在中间3个fork上,可以画一个图进行描述。
这里就需要注意&&和||运算符。
A&&B,如果A=0,就没有必要继续执行&&B了;A非0,就需要继续执行&&B。
A||B,如果A非0,就没有必要继续执行||B了,A=0,就需要继续执行||B。
fork()对于父进程和子进程的返回值是不同的,按照上面的A&&B和A||B的分支进行画图,可以得出5个分支。
加上前面的fork和最后的fork,总共4*5=20个进程,除去main主进程,就是19个进程了。





下面简单介绍一下exec家族:

一、
#include <unistd.h>
 
int execl(const char * path, const char* arg1,...)

参数:
path : 被执行程序名(含完整路径)。
arg1 - argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束

int main(){// 第一个参数需要一个路径,能够找到需要执行的文件// 后面的参数表明执行的方式,和在终端方式类似,如果程序执行需要// 其他的参数 ls -l, 参数要作为函数的实参传过去// 最后需要补一个 NULL// 产生一个新的程序 ,替换了原有的程序,原有的进程id是不变的// int ret = execl("/bin/ls", "ls", "-l", NULL);int ret = execl("/bin/ps", "ps", "-ef", NULL);if (ret == -1){perror("execl");return -1;}printf ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");return 0;}


二、
#include <unistd.h>
 
int execlp(const char * path, const char* arg1,...)
参数:
path : 被执行程序名(不含路径,将从path环境变量中查找该程序)。
arg1 - argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束
int main(){int ret = execlp("ls", "ls", "-l", NULL);if (ret == -1){perror("execl");return -1;}printf ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");return 0;}


三、
#include <unistd.h>
 
int execv(const char * path, const char *argv[])
参数:
path : 被执行程序名(含完整路径)。
argv[]: 被执行程序所需的命令行参数数组
int main(){char *a[] = {"file", NULL};int ret = execv("file", a);if (ret == -1){perror("execl");return -1;}return 0;}

四、
#include <stdlib.h>
 
int system(const char* string)
功能:
调用fork产生子进程,由子进程来调用 /bin/sh -c string来执行参数string所代表的命

int main1(){printf ("hellp world\n");sleep(1);// 在内部fork()一个子进程,调用 /bin/sh -c string来执行system("ps -ef | grep a.out");printf ("aaaaaaaaaaaaaaaaaaaaa\n");return 0;}

终止函数:
exit()和   _exit()
用法:
一、
exit() 和_exit ()区别:
exit()停止进程之前,要检查文件的打开情况,并把文件缓冲区中的内容写回文件才停止进程。

二、
exit(0):正常运行程序并退出程序;
exit(1):非正常运行导致退出程序;
return():返回函数,若在主函数中,则会退出函数并返回一值。
详细说:
1. return返回函数值,是关键字; exit 是一个函数。
2. return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
3. return是函数的退出(返回);exit是进程的退出。
4. return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。exit是一个库函数,exit(1)表示发生错误后退出程序,exit(0)表示正常退出。在stdlib.h中exit函数是这样子定义的:void exit(int status)。这个系统调用是用来终止一个进程的,无论在程序中的什么位置,只要执行exit,进程就会从终止进程的运行。讲到exit这个系统调用,就要提及另外一个系统调用,_exit,_exit()函数位于unistd.h中,相比于exit(),_exit()函数的功能最为简单,直接终止进程的运行,释放其所使用的内存空间,并销毁在内存中的数据结构,而exit()在于在进程退出之前要检查文件的状态,将文件缓冲区中的内容写回文件。
5. return用于结束一个函数的执行,将函数的执行信息传出给其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS或其父进程,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出, 非0 为非正常退出。
6. 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。

参考文献:

https://baike.baidu.com/item/fork/7143171

http://blog.sina.com.cn/s/blog_99f5031a0101lshp.html