---恢复内容开始---

fork函数

该函数是unix中派生新进程的唯一方法。

  #include <unistd.h>

  pid_t   fork(void);

返回: (调用它一次, 它返回 两次 , 它在调用进程(称为父进程)中返回一次, 返回值是新派生进程(称为子进程)的进程ID号

    在子进程又返回一次,返回值为0。 因此,返回值本身告知当前进程是子进程还是父进程)

   在子进程中为0, 在父进程中为子进程ID,

   若出错则为-1;

fork有两个典型的用法:

  1.一个进程创建一个自身的副本,这样每个副本都 可以在另一个副本执行其他任务的同时处理各自的某个操作。 这是网络服务器的典型用法;

  2. 一个进程想要执行另一个程序。既然创建新进程的唯一办法是调用fork, 该进程于是首先调用fork创建一个自身的副本,然后另一个副本(通常为子进程)调用exec把自身替换成新的程序。 这是shell之类程序的典型用法;

  exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行,进程ID并不改变。我们称调用exec的进程为调用进程(calling process),称新执行的程序为新程序(new program)

  #include <unistd.h>

  int  execl(const  char *pathname, const char *arg0,  .../);

  int   execv(const  char  *pathname, char *const  *argv[]);

  int    execle(const char *pathname, const char *arg(), ....);

  int   execve(const char  *pathname,  char *const argv[],  char *const envp[]);

  int   execlp(const  char *filename, con)

并发服务器在listen到连接之后,accept()函数解除阻塞,然后服务器执行fork()函数,在父进程中有listenfd,  和 由 accpet返回的已连接套接字即connfd, 而子进程也存在listenfd, 和由accept返回的已经连接套接字即connfd。

  下一步: 父进程关闭已连接的套接字connfd,保留listenfd继续监听。 子进程关闭listenfd套接字,保留connfd进行相应操作(read, write等操作)

getsockname  和  getpeername函数

===================================================================================================================

  信号(signal) 就是告知某个进程发生了某个事件的通知,  有时也称为 “ software interrupt “ .  信号通常是异步发生的, 也就是说进程预先不知道信号的准确发生的时间;

  信号可以:

    1. 由一个信号发给另有一个进程(或自身)

    2. 由内核发给某个进程;

  每一个信号都有一个与之关联的处置(disposition), 也称为行为(action)。 我们通过调用sigaction函数来设定一个信号的处置,并有三种选择。

  (1) 我们提供一个函数, 只要有特定信号发生它就被调用。   这样的函数称为“信号处理函数( signal handler)”, 这种行为称为 捕获信号(catch signal).

    有两个信号不能被捕获,它们是SIGKILL  和 SIGSTOP。  信号处理函数由信号值这个单一的整数参数来调用, 且没有返回值,

    其函数原型如下:

      void  handler(int  signo);

    对于大多信号来说,调用signcation函数   并指定信号发生所调用的函数  就是捕获信号所需做的全部工作;此外,SIGIO, SIGPOLL, SIGURG这些个别信号还要求捕获它们的进程 做其它额外 的工作;

  (2)我们可以把某个信号的处置设定为SIG_IGN来忽略(ignore)它。  SIGKILL和SIGSTOP这两个信号不能被忽略;

  (3)我们可以把某个信号的处置设定为 SIG_DFL来启用它的默认(default)处理。默认处置通常是在收到信号后终止进程,某些信号的默认default处理不同;

---恢复内容结束---

fork函数

该函数是unix中派生新进程的唯一方法。

  #include <unistd.h>

  pid_t   fork(void);

返回: (调用它一次, 它返回 两次 , 它在调用进程(称为父进程)中返回一次, 返回值是新派生进程(称为子进程)的进程ID号

    在子进程又返回一次,返回值为0。 因此,返回值本身告知当前进程是子进程还是父进程)

   在子进程中为0, 在父进程中为子进程ID,

   若出错则为-1;

fork有两个典型的用法:

  1.一个进程创建一个自身的副本,这样每个副本都 可以在另一个副本执行其他任务的同时处理各自的某个操作。 这是网络服务器的典型用法;

  2. 一个进程想要执行另一个程序。既然创建新进程的唯一办法是调用fork, 该进程于是首先调用fork创建一个自身的副本,然后另一个副本(通常为子进程)调用exec把自身替换成新的程序。 这是shell之类程序的典型用法;

  exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行,进程ID并不改变。我们称调用exec的进程为调用进程(calling process),称新执行的程序为新程序(new program)

  #include <unistd.h>

  int  execl(const  char *pathname, const char *arg0,  .../);

  int   execv(const  char  *pathname, char *const  *argv[]);

  int    execle(const char *pathname, const char *arg(), ....);

  int   execve(const char  *pathname,  char *const argv[],  char *const envp[]);

  int   execlp(const  char *filename, con)

并发服务器在listen到连接之后,accept()函数解除阻塞,然后服务器执行fork()函数,在父进程中有listenfd,  和 由 accpet返回的已连接套接字即connfd, 而子进程也存在listenfd, 和由accept返回的已经连接套接字即connfd。

  下一步: 父进程关闭已连接的套接字connfd,保留listenfd继续监听。 子进程关闭listenfd套接字,保留connfd进行相应操作(read, write等操作)

getsockname  和  getpeername函数

===================================================================================================================

  信号(signal) 就是告知某个进程发生了某个事件的通知,  有时也称为 “ software interrupt “ .  信号通常是异步发生的, 也就是说进程预先不知道信号的准确发生的时间;

  信号可以:

    1. 由一个信号发给另有一个进程(或自身)

    2. 由内核发给某个进程;

  每一个信号都有一个与之关联的处置(disposition), 也称为行为(action)。 我们通过调用sigaction函数来设定一个信号的处置,并有三种选择。

  (1) 我们提供一个函数, 只要有特定信号发生它就被调用。   这样的函数称为“信号处理函数( signal handler)”, 这种行为称为 捕获信号(catch signal).

    有两个信号不能被捕获,它们是SIGKILL  和 SIGSTOP。  信号处理函数由信号值这个单一的整数参数来调用, 且没有返回值,

    其函数原型如下:

      void  handler(int  signo);

    对于大多信号来说,调用signcation函数   并指定信号发生所调用的函数  就是捕获信号所需做的全部工作;此外,SIGIO, SIGPOLL, SIGURG这些个别信号还要求捕获它们的进程 做其它额外 的工作;

  (2)我们可以把某个信号的处置设定为SIG_IGN来忽略(ignore)它。  SIGKILL和SIGSTOP这两个信号不能被忽略;

  (3)我们可以把某个信号的处置设定为 SIG_DFL来启用它的默认(default)处理。默认处置通常是在收到信号后终止进程,某些信号的默认default处理不同;

=======================================================================================================2.1 Linux下进程的结构

  Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。其实学过汇编语言的人一定知道,一般的CPU都有上述三种段寄存器,以方便操作系统的运行。这三个部分也是构成一个完整的执行序列的必要的部分。

  "代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程 序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及 动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。这其中有许多细节问题,这里限于篇幅就不多介绍了。系统如果同时运行数个相同的程 序,它们之间就不能使用同一个堆栈段和数据段。

  如果一个大程序在运行中,它的数据段和堆栈都很大,一次fork就要复制一次,那么fork的系统开销不是很大吗?其实UNIX自有其解决的办法,大家知 道,一般CPU都是以"页"为单位来分配内存空间的,每一个页都是实际物理内存的一个映像,象INTEL的CPU,其一页在通常情况下是 4086字节大小,而无论是数据段还是堆栈段都是由许多"页"构成的,fork函数复制这两个段,只是"逻辑"上的,并非"物理"上的,也就是说,实际执 行fork时,物理空间上两个进程的数据段和堆栈段都还是共享着的,当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,系统就将有区别的" 页"从物理上也分开。系统在空间上的开销就可以达到最小。

exec( )函数族

下面我们来看看一个进程如何来启动另一个程序的执行。在Linux中要使用exec函数族。系统 调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量 (envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp,

  以execlp为例,其它函数究 竟与execlp有何区别,请通过manexec命令来了解它们的具体情况。

  一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码, 废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序 了。(不过exec类函数中有的还允许继承环境变量之类的信息。)

那么如果我的程序想启动另一程序的执行但自己仍想继续运行的话,怎么办呢?那就是结合fork与exec的使用。下面一段代码显示如何启动运行其它程序:

 #include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> char command[];
int main()
{
int rtn;
printf(">>"); fgets(command, , stdin);
command[strlen(command)-] = ;
if(fork()==) //子进程
{
execlp(command, NULL);
perror(command);
exit(errno);
}
else //父进程
{
wait(&rtn);
printf("child process return %d\n", rtn);
} return ;
}

最新文章

  1. 关于Application.Lock和Lock(obj) 转 http://www.cnblogs.com/yeagen/archive/2012/03/01/2375610.html
  2. redis-JedisPoolConfig配置
  3. 编译spock proxy
  4. 分批次从musql取数据,每次取1000条
  5. MongoDB副本集搭建及备份恢复
  6. Android knock code analysis
  7. vb.net之窗体继承
  8. Google的Java编程风格指南(Java编码规范)
  9. Windows7中Emacs 24 shell使用Gitbash
  10. cakephp 的query方法,直接写在controller中是否 有点不合适
  11. 【学习】文本框输入监听事件oninput
  12. pyqt5 动画学习(四) 旋转动画,使用QGraphicsView让自己的控件旋转起来
  13. 作业二:构建swap函数
  14. 创建Java多线程的两种方式和线程异常
  15. Gson 与 fastJson 在使用上的差异(fastJson的优点)
  16. EditPlus 4.3.2543 中文版已经发布(2月3日更新,Emmet 功能回归)
  17. sublime的坑
  18. (转)tomcat+nginx+redis实现均衡负载、session共享(一)
  19. python模块整理29-redis模块
  20. 借助 CORS 从 JavaScript 使用 API 应用

热门文章

  1. linux修改文本模式下的分辨率(CentOS6.4)
  2. Day01
  3. hdu 2102 A计划(双层BFS)(具体解释)
  4. 《Linux命令行与shell脚本编程大全》 第十四章 学习笔记
  5. Tomcat从零开始(十一)WebappLoader概述
  6. BZOJ 2716 Violet 3 天使玩偶 CDQ分治
  7. JavaScript之call()和apply()方法详解
  8. api文档生成工具 C#
  9. 有关android源码编译的几个问题
  10. poj3162 Walking Race