非常想写点关于多进程和多线程的东西,我确实非常爱他们。可是每每想动手写点关于他们的东西,却总是求全心理作祟,始终动不了手。
今天最终下了决心,写点东西,以后能够再修修补补也无妨。
一.为何须要多进程(或者多线程),为何须要并发?
这个问题也许本身都不是个问题。可是对于没有接触过多进程编程的朋友来说,他们确实无法感受到并发的魅力以及必要性。
我想,仅仅要你不是整天都写那种int main()究竟的代码的人,那么或多或少你会遇到代码响应不够用的情况,也应该有尝过并发编程的甜头。就像一个快餐点的服务员,既要在前台接待客户点餐,又要接电话送外卖,没有分身术肯定会忙得你焦头烂额的。幸运的是确实有这么一种技术,让你能够像孙悟空一样分身,灵魂出窍,乐哉乐哉地轻松应付一切状况,这就是多进程/线程技术。
并发技术,就是能够让你在同一时间同一时候运行多条任务的技术。你的代码将不不过从上到下,从左到右这样规规矩矩的一条线运行。你能够一条线在main函数里跟你的客户交流,还有一条线,你早就把你外卖送到了其它客户的手里。
所以,为何须要并发?由于我们须要更强大的功能,提供很多其它的服务,所以并发,不可缺少。
二.多进程
什么是进程。最直观的就是一个个pid,官方的说法就:进程是程序在计算机上的一次运行活动。
说得简单点,以下这段代码运行的时候
int main() { printf(”pid is %d/n”,getpid() ); return 0; }
进入main函数,这就是一个进程,进程pid会打印出来,然后执行到return,该函数就退出,然后因为该函数是该进程的唯一的一次执行,所以return后,该进程也会退出。
看看多进程。linux下创建子进程的调用是fork();
#include <unistd.h> #include <sys/types.h> #include <stdio.h> void print_exit() { printf("the exit pid:%d/n",getpid() ); } main () { pid_t pid; atexit( print_exit ); //注冊该进程退出时的回调函数 pid=fork(); if (pid < 0) printf("error in fork!"); else if (pid == 0) printf("i am the child process, my process id is %d/n",getpid()); else { printf("i am the parent process, my process id is %d/n",getpid()); sleep(2); wait(); } }
i am the child process, my process id is 15806
the exit pid:15806
i am the parent process, my process id is 15805
the exit pid:15805
这是gcc測试下的执行结果。
关于fork函数,功能就是产生子进程,因为前面说过,进程就是运行的流程活动。
那么fork产生子进程的表现就是它会返回2次,一次返回0,顺序运行以下的代码。这是子进程。
一次返回子进程的pid,也顺序运行以下的代码,这是父进程。
(为何父进程须要获取子进程的pid呢?这个有非常多原因,当中一个原因:看最后的wait,就知道父进程等待子进程的终结后,处理其task_struct结构,否则会产生僵尸进程,扯远了,有兴趣能够自己google)。
假设fork失败,会返回-1.
额外说下atexit( print_exit ); 须要的參数肯定是函数的调用地址。
这里的print_exit 是函数名还是函数指针呢?答案是函数指针,函数名永远都仅仅是一串没用的字符串。
某本书上的规则:函数名在用于非函数调用的时候,都等效于函数指针。
说到子进程仅仅是一个额外的流程,那他跟父进程的联系和差别是什么呢?
我非常想建议你看看linux内核的注解(有兴趣能够看看,那里才有本质上的了解),总之,fork后,子进程会复制父进程的task_struct结构,并为子进程的堆栈分配物理页。理论上来说,子进程应该完整地复制父进程的堆,栈以及数据空间,可是2者共享正文段。