进程ID

1 进程id是唯一的。(不会有进程id一样的两个进程)

2进程id是可复用的,一个进程销毁后,它的id号可以被新的进程使用。但是Unix采用了延迟复用的算法,也就是进程   销毁后它的id不会立即被使用。

3 进程id为0的是调度进程。这是系统进程,是内核的一部分。

4 进程id为1的是init进程。init进程读取初始化文件/etc/rc*files 或者/etc/inittab,以及在/etc/init.d中的文件,使系统处于      某种状态。 init进程是用户进程,而不是系统进程。

进程id相关函数

  1. #include <unistd.h>
  2. pid_t getpid(void);
  3. Returns: process ID of calling process
  4. pid_t getppid(void);
  5. Returns: parent process ID of calling process
  6. uid_t getuid(void);
  7. Returns: real user ID of calling process
  8. uid_t geteuid(void);
  9. Returns: effective user ID of calling process
  10. gid_t getgid(void);
  11. Returns: real group ID of calling process
  12. gid_t getegid(void);
  13. Returns: effective group ID of calling process

创建新进程

#include <unistd.h>
pid_t fork(void);
Returns: 0 in child, process ID of child in parent,−1 on error
Unix可以使用系统函数fork()创建一个新进程。
    fork()执行一次返回两次。
    返回值:
        0: 
          表示子进程
        子进程id: 表示父进程
     子进程可以通过getppid()来获取父进程id,所以只需要返回0,表示创建成功即可.而对于父进程来说,他无从得知子进程的id,因此在创建的时候就应该吧子进程的Id号返回给他。

    我们知道,每个进程都会涉及到进程控制块、正文段、数据段,三部分内容。
    进程控制块是每个进程独有的,这就不用多说。 
    正文段里面是程序的指令,都是只读的,因此父进程和子进程可以共享这部分内容 。share
    数据段:  子进程会拷贝一份父进程的数据段(数据空间、堆、栈)。注意:这里是copy而不是share

    由于我们知道,一般创建子进程后,进阶着就是使用exec替换子进程为一个新的程序了,这是父进程的数据段内容就没什么用了。因此,现代系统在实现的时候,采用了写时复制copy-on-write(COW)。该方法就是内核将数据段设置为共享share,但它是只读的,当父进程或者子进程下需要对数据进行修改时,就自己copy一个副本。

    Example
#include "apue.h"
#include "myerr.h"
int globvar=6;/*external variable in initialized data */
char buf[] = "a write to stdout\n";
int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
err_sys("write error");
printf("before fork\n"); /* we don’t flush stdout */
if ((pid = fork()) < 0) {
err_sys("fork error");
}else if (pid == 0) { /* child */
globvar++; /* modify variables */
var++;
}else {
sleep(2); /* parent */
}
printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
exit(0);
}
执行结果:
windeal@ubuntu:~/Windeal/apue$ ./exe
a write to stdout
before fork
pid = 4523, glob = 7, var = 89
pid = 4522, glob = 6, var = 88
windeal@ubuntu:~/Windeal/apue$

在这个例子中,我们在子进程中对globvar和var都进行自加,然后又在父进程中sleep(2),使得子进程先执行。
最终结果,父进程的数据都没变,子进程globvar和var都变成了新的值。
    从例子中可以看出,正文段是共享的,都使用了printf语句(你要说是copy,我就不跟你辩了。。。)
vfork()
    功能与fork()基本相似。

    不同点:
        vfork保证子进程先执行,也就是子进程执行了exec程序或者exit后才执行fork()。如果子进程中有依赖父进程的下一步动作才能执行的部分,可能会导致死锁。
        vfork创建的子进程会共享父进程的数据段。也就是说它会改变父进程的数据。
#include "apue.h"
#include "myerr.h"
int globvar=6;/*external variable in initialized data */
int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
printf("before vfork\n"); /* we don’t flush stdio */
if ((pid = vfork()) < 0) {
err_sys("vfork error");
}else if (pid == 0) { /* child */
globvar++; /* modify parent’s variables */
var++;
_exit(0); /* child terminates */
}
/* parent continues here */
printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
exit(0);
}

执行结果:
windeal@ubuntu:~/Windeal/apue$ ./exe
before vfork
pid = 6298, glob = 7, var = 89
windeal@ubuntu:~/Windeal/apue$

可以看到父进程globvar和var被子进程改变了。

        vfork()被一些版本视为过时的接口,一般不使用。所以不必过多研究,多用fork()来创建新进程即可。


APUE学习笔记——8.1-8.4 进程基础的更多相关文章

  1. apue学习笔记(第七章 进程环境)

    本章将了解进程的环境. main函数 C程序总是从main函数开始执行,main函数的原型是: int main(int argc,char *argv[]); 其中,argc是命令行参数的数目,ar ...

  2. APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause

    转载注明出处:Windeal学习笔记 kil和raise kill()用来向进程或进程组发送信号 raise()用来向自身进程发送信号. #include <signal.h> int k ...

  3. APUE学习笔记3_文件IO

    APUE学习笔记3_文件IO Unix中的文件IO函数主要包括以下几个:open().read().write().lseek().close()等.这类I/O函数也被称为不带缓冲的I/O,标准I/O ...

  4. 大数据学习笔记——Java篇之网络编程基础

    Java网络编程学习笔记 1. 网络编程基础知识 1.1 网络分层图 网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型:后者为实际应用的模型,具体对 ...

  5. [原创]java WEB学习笔记49:文件上传基础,基于表单的文件上传,使用fileuoload 组件

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  6. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

  7. C++学习笔记(一):C++基础知识

    一.C++基础知识 新的数据类型 C语言中的数据类型 C++中新的数据类型 思考:新的数据类型有什么好处?请看下面的代码: 可以见得:新的类型使整个程序更加简洁,程序变得易读易懂!这个就是bool类型 ...

  8. 数字图像处理学习笔记之一 DIP绪论与MATLAB基础

    写在前面的话 数字图像处理系列的学习笔记是作者结合上海大学计算机学院<数字图像处理>课程的学习所做的笔记,使用参考书籍为<冈萨雷斯数字图像处理(第二版)(MATLAB版)>,同 ...

  9. java学习笔记(1)java的基础介绍 、JDK下载、配置环境变量、运行java程序

    java工程师是开发软件的 什么是软件呢? 计算机包括两部分: 硬件: 鼠标.键盘.显示器.主机箱内部的cpu.内存条.硬盘等 软件: 软件包括:系统软件和应用软件 系统软件:直接和硬件交互的软件:w ...

随机推荐

  1. 关于Log4Net的使用和配置

    1. 添加log4net.dll引用 2.在添加引用的那层的 AssemblyInfo.cs         注册   : [assembly: log4net.Config.XmlConfigura ...

  2. 安卓Android第三方登录-QQ登录

    要实现QQ第三方登录,其实只需要一个封装类:QQLoginManager 几乎 三行代码 就实现QQ登录功能 这里先给出Github开源项目地址,项目下有详细的使用说明   下面就开始详细说一说怎么实 ...

  3. [Linux 002]——Linux的常用命令

    经过前面的学习,大概了解了计算机组成原理和操作系统的一些知识.尽管这些知识都是琐碎的,拼凑的,在以后的工作和学习中仍需进行深入的了解.但是这些预备知识对于准备跨入 Linux 大门的童鞋来说,应该是足 ...

  4. 20145324 《Java程序设计》第6周学习总结

    20145324 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 1.使用输入串流将数据从来源取出 InputStream 使用输出串流将数据写入目的地 OutStream ...

  5. shall的过去式和should怎么区分

    shall的过去式是should,但是怎么和情态动词的should区分啊,答得好我会提高悬赏!!! shall 将来时,用于第一人称:I shall be back in a minute.用来表示征 ...

  6. 广播机制的CS模型实现

    广播机制的cs模型实现如下: 首先可以使用ifconfig命令查看自己所在网段的广播地址 server.c #include<stdio.h> #include<unistd.h&g ...

  7. Hive的Explain命令

    Hive的Explain命令,用于显示SQL查询的执行计划. Hive查询被转化成序列阶段(这是一个有向无环图).这些阶段可能是mapper/reducer阶段,或者是Metastore或文件系统的操 ...

  8. ubuntu18.04 64bit如何安装docker

    注:参考自https://docs.docker.com/install/linux/docker-ce/ubuntu/ 1.卸载旧版本docker(如果之前安装了) sudo apt-get rem ...

  9. 使用百度地图LBS创建自定义标注

    <body> <div id="allmap"></div> <div class="sel_container" i ...

  10. linux基础之Vim