一. 进程的开始和结束

  1.1. main函数的调用

    a. 编译链接时的引导代码。操作系统下的应用程序其实在main执行前也需要先执行一段引导代码才能去执行main,我们写应用程序时不用考虑引导代码的问题,编译连接时(准确说是连接时)由链接器将编译器中事先准备好的引导代码给连接进去和我们的应用程序一起构成最终的可执行程序。

    b. 运行时的加载器。加载器是操作系统中的程序,当我们去执行一个程序时(譬如./a.out,譬如代码中用exec族函数来运行)加载器负责将这个程序加载到内存中去执行这个程序。

    c. 程序在编译连接时用链接器,运行时用加载器,这两个东西对程序运行原理非常重要

  1.2. 进程如何结束

    1.2.1. 在main(main函数由其父进程调用,故返回后进程就over)用return,一般原则是程序正常终止return 0,如果程序异常终止则return -1。
    1.2.2.  一般终止进程(程序)应该使用exit或者_exit或者_Exit之一。

    1.2.3. atexit注册进程终止处理函数

    1.2.4. return、exit和_exit的区别:return和exit效果一样,都是会执行进程终止处理函数,但是用_exit终止进程时并不执行atexit注册的进程终止处理函数。

    1.2.5. atexit注册多个进程终止处理函数,先注册的后执行(先进后出,和栈一样)

    实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> void func1(void)
{
printf("func1\n");
} void func2(void)
{
printf("func2\n");
} int main(void)
{
printf("hello world.\n"); // 当进程被正常终止时,系统会自动调用这里注册的func1执行
atexit(func2);
atexit(func1); printf("my name is lilei hanmeimei\n"); //return 0;
//exit(0);
_exit();
}

二. 进程环境

  2.1. 环境变量 export查看   

root@ubuntu:/home/yaofeng# export
declare -x CLUTTER_IM_MODULE="xim"
declare -x COLORTERM="gnome-terminal"
declare -x COMPIZ_CONFIG_PROFILE="ubuntu"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-6jtZuUHMzw"
declare -x DEFAULTS_PATH="/usr/share/gconf/ubuntu.default.path"
declare -x DESKTOP_SESSION="ubuntu"
declare -x DISPLAY=":0"
declare -x GDMSESSION="ubuntu"
declare -x GDM_LANG="en_US"
declare -x GNOME_DESKTOP_SESSION_ID="this-is-deprecated"
declare -x GNOME_KEYRING_CONTROL="/run/user/1000/keyring-h2Nd3d"
declare -x GNOME_KEYRING_PID=""
declare -x GPG_AGENT_INFO="/run/user/1000/keyring-h2Nd3d/gpg:0:1"
declare -x GTK_IM_MODULE="ibus"
declare -x GTK_MODULES="overlay-scrollbar:unity-gtk-module"
declare -x HOME="/root"
declare -x IM_CONFIG_PHASE=""
declare -x INSTANCE="Unity"
declare -x JOB="gnome-session"
declare -x LANG="en_US.UTF-8"
declare -x LANGUAGE="en_US"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LOGNAME="root"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
declare -x MAIL="/var/mail/root"
declare -x MANDATORY_PATH="/usr/share/gconf/ubuntu.mandatory.path"
declare -x OLDPWD
declare -x PATH="/usr/local/arm/arm-2009q3/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
declare -x PWD="/home/yaofeng"
declare -x QT4_IM_MODULE="xim"
declare -x QT_IM_MODULE="ibus"
declare -x SELINUX_INIT="YES"
declare -x SESSIONTYPE="gnome-session"
declare -x SHELL="/bin/bash"
declare -x SHLVL=""
declare -x SSH_AGENT_LAUNCHER="upstart"
declare -x SSH_AGENT_PID=""
declare -x SSH_AUTH_SOCK="/run/user/1000/keyring-h2Nd3d/ssh"
declare -x TERM="xterm"
declare -x TEXTDOMAIN="im-config"
declare -x TEXTDOMAINDIR="/usr/share/locale/"
declare -x UBUNTU_MENUPROXY=""
declare -x UPSTART_EVENTS="started starting"
declare -x UPSTART_INSTANCE=""
declare -x UPSTART_JOB="unity-settings-daemon"
declare -x UPSTART_SESSION="unix:abstract=/com/ubuntu/upstart-session/1000/2188"
declare -x USER="root"
declare -x VTE_VERSION=""
declare -x WINDOWID=""
declare -x XAUTHORITY="/home/yaofeng/.Xauthority"
declare -x XDG_CONFIG_DIRS="/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg"
declare -x XDG_CURRENT_DESKTOP="Unity"
declare -x XDG_DATA_DIRS="/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/"
declare -x XDG_GREETER_DATA_DIR="/var/lib/lightdm-data/yaofeng"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SEAT="seat0"
declare -x XDG_SEAT_PATH="/org/freedesktop/DisplayManager/Seat0"
declare -x XDG_SESSION_ID="c2"
declare -x XDG_SESSION_PATH="/org/freedesktop/DisplayManager/Session0"
declare -x XDG_VTNR=""
declare -x XMODIFIERS="@im=ibus"
root@ubuntu:/home/yaofeng#

  2.2. 进程中使用环境变量

    a. .每一个进程中都有一份所有环境变量构成的一个表格,也就是说我们当前进程中可以直接使用这些环境变量。进程环境表其实是一个字符串数组,用environ变量指向它。

    b. 每个进程中环境变量是独立的,可以独自修改环境变量并不会改变其他进程的环境变量

    c. 环境变量使用

#include <stdio.h>

int main(void)
{
extern char **environ; // 声明就能用
int i = ; while (NULL != environ[i])
{
printf("%s\n", environ[i]);
i++;
} return ;
}

    d. 获取指定环境变量函数getenv

三. 进程介绍

  3.1. 什么是进程

    a. 动态过程而不是静态实物
    b. 进程就是程序的一次运行过程,一个静态的可执行程序a.out的一次运行过程(./a.out去运行到结束)就是一个进程。
    c. 进程控制块PCB(process control block),内核中专门用来管理一个进程的数据结构。

  3.2. 进程PID

    a. PID是程序被操作系统加载到内存成为进程后动态分配的资源

    b. 获取PID相关API:getpid、getppid、getuid、geteuid、getgid、getegid

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> int main(void)
{
pid_t p1 = -, p2 = -; printf("hello.\n");
p1 = getpid();
printf("pid = %d.\n", p1);
p2 = getppid();
printf("parent id = %d.\n", p2); return ;
}

    c. 进程查看命令ps

      (1)ps -ajx 偏向显示各种有关的ID号
      (2)ps -aux 偏向显示进程各种占用资源

root@ubuntu:/home/yaofeng# ps
PID TTY TIME CMD
pts/ :: su
pts/ :: bash
pts/ :: ps
root@ubuntu:/home/yaofeng# ps -ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
? - Ss : /sbin/init
? - S : [kthreadd]
root@ubuntu:/home/yaofeng# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 0.0 0.2 ? Ss : : /sbin/init
root 0.0 0.0 ? S : : [kthreadd]
root 0.0 0.0 ? S : : [ksoftirqd/]
root 0.0 0.0 ? S : : [kworker/:]

  3.2. 子进程创建

    3.2.1. fork创建子进程

      a. 进程的分裂生长模式。如果操作系统需要一个新进程来运行一个程序,那么操作系统会用一个现有的进程来复制生成一个新进程。老进程叫父进程,复制生成的新进程叫子进程

      b. fork创建一个新进程。这个系统调用复制当前进程,在进程表中创建一个新的表项,新的表项中的许多属性与当前进程是相同的。新进程几乎与原进程一模一样,执行的代码也完全相同,但新的进程有自己的数据空间,环境和文件描述符

      c. fork函数返回值等于0则此时程序在子进程中执行,而返回值大于0则在父进程中执行。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> int main(void)
{
pid_t p1 = -; p1 = fork(); // 返回2次 if (p1 == )
{
// 这里一定是子进程 // 先sleep一下让父进程先运行,先死
sleep(); printf("子进程, pid = %d.\n", getpid());
printf("hello world.\n");
printf("子进程, 父进程ID = %d.\n", getppid());
} if (p1 > )
{
// 这里一定是父进程
printf("父进程, pid = %d.\n", getpid());
printf("父进程, p1 = %d.\n", p1);
} if (p1 < )
{
// 这里一定是fork出错了
} // 在这里所做的操作
//printf("hello world, pid = %d.\n", getpid()); return ;
}

  3.3. 父子进程间的藕断丝连

    a. 子进程有自己独立的PCB

    b. 子进程被内核同等调度

    c. 子进程几乎与父进程一模一样,执行的代码也完全相同,但新的进程有自己的数据空间,环境和文件描述符

  3.4. 进程的消亡

    3.4.1. 进程资源的回收

      a. linux系统设计时规定:每一个进程退出时,操作系统会自动回收这个进程涉及到的所有的资源(譬如malloc申请的内容没有free时,当前进程结束时这个内存会被释放,譬如open打开的文件没有close的在程序终止时也会被关闭)。但是操作系统只是回收了这个进程工作时消耗的内存和IO,而并没有回收这个进程本身占用的内存(8KB,主要是task_struct和栈内存)

    3.4.2. 僵尸进程

      a. 子进程先于父进程结束。子进程结束后父进程此时并不一定立即就能帮子进程“收尸”,在这一段(子进程已经结束且父进程尚未帮其收尸)子进程就被成为僵尸进程。

      b. 子进程除task_struct和栈外其余内存空间皆已清理
      c. 父进程可以使用wait或waitpid以显式回收子进程的剩余待回收内存资源并且获取子进程退出状态。
      d. 父进程也可以不使用wait或者waitpid回收子进程,此时父进程结束时一样会隐式回收子进程的剩余待回收内存资源。(这样设计是为了防止父进程忘记显式调用wait/waitpid来回收子进程从而造成内存泄漏)
    3.4.3. 孤儿进程
      a. 父进程先于子进程结束,子进程成为一个孤儿进程。
      b. linux系统规定:所有的孤儿进程都自动成为一个特殊进程(进程1,也就是init进程)的子进程

  3.5. 父进程wait回收子进程函数介绍

    3.5.1. wait的工作原理

      a. 子进程结束时,系统向其父进程发送SIGCHILD信号

      b. 父进程调用wait函数后阻塞
      c. 父进程被SIGCHILD信号唤醒然后去回收僵尸子进程
      d. 若父进程没有任何子进程则wait返回错误

    3.5.2. wait应用

      3.5.2.1.  wait的参数status。status用来返回子进程结束时的状态,父进程通过wait得到status后就可以知道子进程的一些结束状态信息

        a. WIFEXITED宏用来判断子进程是否正常终止(return、exit、_exit退出)

        b. WIFSIGNALED宏用来判断子进程是否非正常终止(被信号所终止)
        c. WEXITSTATUS宏用来得到正常终止情况下的进程返回值的。

      3.5.2.2. wait的返回值pid_t,这个返回值就是本次wait回收的子进程的PID

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h> int main(void)
{
pid_t pid = -;
pid_t ret = -;
int status = -; pid = fork();
if (pid > )
{
// 父进程
//sleep(1);
printf("parent.\n");
ret = wait(&status); printf("子进程已经被回收,子进程pid = %d.\n", ret);
printf("子进程是否正常退出:%d\n", WIFEXITED(status));
printf("子进程是否非正常退出:%d\n", WIFSIGNALED(status));
printf("正常终止的终止值是:%d.\n", WEXITSTATUS(status));
}
else if (pid == )
{
// 子进程
printf("child pid = %d.\n", getpid());
return ;
//exit(0);
}
else
{
perror("fork");
return -;
} return ;
}

    3.5.3. waitpid介绍

      3.5.3.1. waitpid和wait差别

        a. 基本功能一样,都是用来回收子进程
        b. waitpid可以回收指定PID的子进程
        c. waitpid可以阻塞式或非阻塞式两种工作模式

      3.5.3.2. 使用说明

        a. ret = waitpid(-1, &status, 0); -1表示不等待某个特定PID的子进程而是回收任意一个子进程,0表示用默认的方式(阻塞式)来进行等待,返回值ret是本次回收的子进程的PID
        b. ret = waitpid(pid, &status, 0); 等待回收PID为pid的这个子进程,如果当前进程并没有一个ID号为pid的子进程,则返回值为-1;如果成功回收了pid这个子进程则返回值为回收的进程的PID
        c. ret = waitpid(pid, &status, WNOHANG);这种表示父进程要非阻塞式的回收子进程。此时如果父进程执行waitpid时子进程已经先结束等待回收则waitpid直接回收成功,返回值是回收的子进程的PID;如果父进程waitpid时子进程尚未结束则父进程立刻返回(非阻塞),但是返回值为0(表示回收不成功)。

参考文献《朱老师. linux进程全解》

linux 进程1的更多相关文章

  1. Linux进程管理及while循环

    目录 进程的相关概念 进程查看及管理工具的使用 Linux系统作业控制 调整进程优先级 网络客户端工具 bash之while循环 20.1.进程类型 守护进程 daemon,在系统引导过程中启动的进程 ...

  2. 如何灵活运用Linux 进程资源监控和进程限制

    导读 每个 Linux 系统管理员都应该知道如何验证硬件.资源和主要进程的完整性和可用性.另外,基于每个用户设置资源限制也是其中一项必备技能. 在这篇文章中,我们会介绍一些能够确保系统硬件和软件正常工 ...

  3. TODO:Golang Linux进程退出说明

    TODO:Golang Linux进程退出说明 Golang使用os.Exit(code)进程退出导致当前程序退出并返回给定的状态代码.传统上,code代码为零表示成功退出,非零错误退出. sysca ...

  4. Linux进程管理子系统分析【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51298732 Linux进程管理: 进程与程序: 程序:存放在磁盘上的一系列代码 ...

  5. 12个Linux进程管理命令介绍(转)

    12个Linux进程管理命令介绍 [日期:2015-06-02] 来源:Linux中国  作者:Linux [字体:大 中 小]   执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的 ...

  6. linux 进程管理相关内容

    简介 当我们运行程序时,Linux会为程序创建一个特殊的环境,该环境包含程序运行需要的所有资源,以保证程序能够独立运行,不受其他程序的干扰.这个特殊的环境就称为进程. 每个 Linux 命令都与系统中 ...

  7. Linux - 进程查看与管理

    标签(空格分隔): Linux 进程的静态查看 查看系统所有进程 ps -ef -- 输出来好乱,看不懂..: ps aux -- a表示所有与终端相关的进程,u表示所有以用户组织的进程状态的信息,x ...

  8. Linux进程关系

    Linux进程关系   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux的进程相互之间有一定的关系.比如说,在Linux ...

  9. Linux进程基础

    Linux进程基础   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 计算机实际上可以做的事情实质上非常简单,比如计算两个数的和 ...

  10. linux进程编程:子进程创建及执行函数简介

    linux进程编程:子进程创建及执行函数简介 子进程创建及执行函数有三个: (1)fork();(2)exec();(3)system();    下面分别做详细介绍.(1)fork()    函数定 ...

随机推荐

  1. 运维工程师之IDC系列

    因为我公司在用浪潮服务器,所以说链接暂时是浪潮服务器 1.用UltraISO制作U盘启动安装系统  链接 http://www.4008600011.com/archives/8816 ones 刻录 ...

  2. LeetCode - 乘积最大子串

    给定一个整数数组 nums ,找出一个序列中乘积最大的连续子串(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6. 示例 2: ...

  3. linux-网络管理-6

    Hub 集线器 物理层设备 多端口中继器,不记忆MAC地址 以太网桥 OSI第二层数据链路层 扩展了网络带宽 分割了网络冲突域,使网络冲突被限制在最小的范围内 交换机作为更加智能的交换设备,能够提供更 ...

  4. java实现视频断点上传文件

    一.概述 所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载.在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了.一般断点下载时才用到Range和Content- ...

  5. js怎么上传文件夹

    1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...

  6. dell笔记本 win10 下安装 ubuntu16.04 踩坑记录

    硬件配置情况: dell笔记本-灵越-5577 —— I5七代(带有集显),8G内存条DDR4,GTX1050,128G固态硬盘,1T机械硬盘. 固态硬盘划分为3部分,100GB给win10的C盘,1 ...

  7. QGIS源码解析和二次开发

    使用Python 开发一个交通系统? 不如基于GeoServer来开发更能产生效益 QGIS3d:https://blog.csdn.net/shi_weihappy/article/details/ ...

  8. 在Eclipse中搭建Android开发环境

    忙活了两天多的时间,终于在Eclipse中成功搭建了Android开发环境,着实不易啊!! 原本我用的编译器是MyEclipse的,但是从网上找不到如何在MyEclipse中搭建环境,于是乎就换了Ec ...

  9. 错误1919,配置ODBC数据源MS Access Database时发生错误ODEC错误

    WIN7 64位旗舰版安装OFFICE2003 提示:“错误1919,配置ODBC数据源MS Access Database时发生错误ODEC错误” 在64位系统上,32位软件的注册表的信息不是直接在 ...

  10. 把一个树莓派SD卡系统和文件迁移到空SD卡中

    1.打开win32diskimager软件读出SD卡树莓派系统和文件到电脑的镜像文件中, 2.使用 SD card formatter 格式化SD卡 3.再用win32diskimager往空SD卡写 ...