进程

进程可以产生一个或多个子进程,但最终都要死亡。进程没没有性别差异—每个进程都只有一个父亲。

从内核观点来看,担当分配系统资源(CPU时间,内存等)的实体。

早期的进程:当一个进程创建时,它几乎与父进程相同。它接收父进程地址空间的(逻辑)拷贝,并从进程创建系统调用下一条指令开始执行与父进程相同的代码。
现代的进程:多线程应用程序—拥有很对独立执行流的用户程序共享程序的大部分数据结构。现在,大部分多线程应用程序都是用pthread(POSIX thread)库的标准函数集编写的。

子进程

调用了fork()函数会发生什么?
fork()函数启动了一个新的进程,这个进程几乎是当前进程的一个拷贝。
对于父进程来说,fork函数返回了子进程的进程号。
而对于子进程来说,fork函数则返回0.

fork复制只是逻辑上的复制,物理上的都还在共享,由相应的内存描述符组成。

进程创建

Unix操作系统紧紧依赖进程创建来满足用户的需求。例如,只要一个用户输入一条命令,shell进程就创建一个新进程,新进程执行shell的另一个拷贝。

传统的Unix以统一的方式对待所有进程:子进程复制父进程所拥有的资源,这种方法使得进程创建慢效率低,因为子进程需要拷贝父进程的整个地址空间。

现代Unix内核通过引入三种不同机制来解决这个问题:

  • 写时复制技术允许父子进程读相同的物理页。只要两者中一个试图写一个物理页,内核就把这个页的内容拷贝到一个新的物理页中,并把这个物理页分配给正在写的进程。
  • 轻量级进程允许父子进程共享每进程在内核的很多数据结构,如页表(也就是整个用户态地址空间),打开文件表及信号处理。
  • vfork()系统创建的进程能共享父进程的内存地址空间。

clone,fork,vfork

  • Linux中,轻量级进程由clone()函数创建的
    这个函数使用下列参数:
    1. fn:指定一个由新进程执行的函数。当这个函数返回时,子进程终止。函数返回一个整数,表示子进程的退出代码。
    2. arg:指向传递给fn()函数的数据
    3. flags:各种各样的信息
    4. child_stack:表示把用户态堆栈指针赋给子进程的esp寄存器。调用进程应该总是为子进程分配新的堆栈。
    5. tls:表示线程局部存储段(TLS)数据结构的地址
    6. ptid:表示父进程的用户态变量地址,该父进程具有与轻量级进程相同的PID。
    7. ctid:表示新轻量级进程的用户态变量地址,该进程具有这一类进程的PID。
  • 传统的fork()系统调用在Linux中是用clone()来实现的
  • 前面描述的vfork()系统调用在Linux也是用clone()实现的。
  • do_fork()函数负责处理clone(),fork()和vfork()系统调用

exec()函数族

系统调用execve()对当前进程进行切换,替换为一个指定的程序,其参数包括文件名,参数列表以及环境变量。

一旦一个进程调用了exec类函数,它本身就死亡了,系统把代码替换为程序的代码,废弃原有的数据段和堆栈段,并分配新的,进程号不变。

如果我的程序想启动另一程序的执行但是自己仍然想继续运行的话怎么办?那就是结合fork和exec的使用。

你可能感兴趣的:(计算机知识)