Linux系统编程系列(16篇管饱,吃货都投降了!)
16、 Linux系统编程系列之线程池
一、什么是进程
关于进程的定义很多,这里讲一种比较直接的,进程就是程序中的代码和数据被加载到内存中运行的过程,就是程序的执行过程。进程是动态的,而程序是静态的。程序存储在硬盘里,进程只有在程序被执行后,才存在,而且存在于内存中。具体看下图:
在Linux系统中,程序的格式都是ELF,这些文件在被执行的瞬间,就被载入内存,所谓的载入内存,如上图所示,就是将数据段,代码段这些运行时必要的资源拷贝到内存,另外系统会再分配相应的栈、堆等内存空间给这个进程,使之成为一个动态的实体。
二、进程的组织方式
在Linux系统中,除了系统的初始进程之外,其余所有的进程都是从一个父进程fork而来的,因此,所有的进程都起源于相同的初始进程,它们之间形成一棵倒置的进程树,使用命令pstree查看进程的关系:
gec@ubuntu:~$ pstree
systemd─┬─ModemManager───2*[{ModemManager}]
├─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─accounts-daemon───2*[{accounts-daemon}]
├─acpid
├─anacron
├─apt.systemd.dai───apt.systemd.dai───unattended-upgr───2*[{unattended-upgr}]
├─avahi-daemon───avahi-daemon
├─bluetoothd
├─colord───2*[{colord}]
├─cron
├─cups-browsed───2*[{cups-browsed}]
├─cupsd
├─2*[dbus-daemon]
├─fcitx
├─fcitx-dbus-watc
├─gdm3─┬─gdm-session-wor─┬─gdm-x-session─┬─Xorg───{Xorg}
│ │ │ ├─gnome-session-b─┬─fcitx
│ │ │ │ ├─ssh-agent
│ │ │ │ └─2*[{gnome-session-b}]
│ │ │ └─2*[{gdm-x-session}]
│ │ └─2*[{gdm-session-wor}]
│ └─2*[{gdm3}]
├─gnome-keyring-d───3*[{gnome-keyring-d}]
├─irqbalance───{irqbalance}
├─2*[kerneloops]
├─networkd-dispat
├─polkitd───2*[{polkitd}]
├─rsyslogd───3*[{rsyslogd}]
├─rtkit-daemon───2*[{rtkit-daemon}]
├─snapd───12*[{snapd}]
├─sshd
├─switcheroo-cont───2*[{switcheroo-cont}]
├─systemd─┬─(sd-pam)
│ ├─at-spi-bus-laun─┬─dbus-daemon
│ │ └─3*[{at-spi-bus-laun}]
│ ├─at-spi2-registr───2*[{at-spi2-registr}]
│ ├─dbus-daemon
│ ├─dconf-service───2*[{dconf-service}]
│ ├─evolution-addre───5*[{evolution-addre}]
│ ├─evolution-calen───8*[{evolution-calen}]
│ ├─evolution-sourc───3*[{evolution-sourc}]
│ ├─gjs───4*[{gjs}]
│ ├─gnome-session-b─┬─evolution-alarm───5*[{evolution-alarm}]
│ │ ├─gsd-disk-utilit───2*[{gsd-disk-utilit}]
│ │ ├─update-notifier───3*[{update-notifier}]
│ │ └─3*[{gnome-session-b}]
│ ├─gnome-session-c───{gnome-session-c}
│ ├─gnome-shell─┬─ibus-daemon─┬─ibus-engine-sim───2*[{ibus-engine-sim}]
│ │ │ ├─ibus-extension-───3*[{ibus-extension-}]
│ │ │ ├─ibus-memconf───2*[{ibus-memconf}]
│ │ │ └─2*[{ibus-daemon}]
│ │ └─7*[{gnome-shell}]
│ ├─gnome-shell-cal───5*[{gnome-shell-cal}]
│ ├─gnome-terminal-─┬─bash───pstree
│ │ ├─bash
│ │ └─4*[{gnome-terminal-}]
│ ├─goa-daemon───3*[{goa-daemon}]
│ ├─goa-identity-se───2*[{goa-identity-se}]
│ ├─gsd-a11y-settin───3*[{gsd-a11y-settin}]
│ ├─gsd-color───3*[{gsd-color}]
│ ├─gsd-datetime───3*[{gsd-datetime}]
│ ├─gsd-housekeepin───3*[{gsd-housekeepin}]
│ ├─gsd-keyboard───3*[{gsd-keyboard}]
│ ├─gsd-media-keys───3*[{gsd-media-keys}]
│ ├─gsd-power───3*[{gsd-power}]
│ ├─gsd-print-notif───2*[{gsd-print-notif}]
│ ├─gsd-printer───2*[{gsd-printer}]
│ ├─gsd-rfkill───2*[{gsd-rfkill}]
│ ├─gsd-screensaver───2*[{gsd-screensaver}]
│ ├─gsd-sharing───3*[{gsd-sharing}]
│ ├─gsd-smartcard───4*[{gsd-smartcard}]
│ ├─gsd-sound───3*[{gsd-sound}]
│ ├─gsd-usb-protect───3*[{gsd-usb-protect}]
│ ├─gsd-wacom───2*[{gsd-wacom}]
│ ├─gsd-wwan───3*[{gsd-wwan}]
│ ├─gsd-xsettings───3*[{gsd-xsettings}]
│ ├─gvfs-afc-volume───3*[{gvfs-afc-volume}]
│ ├─gvfs-goa-volume───2*[{gvfs-goa-volume}]
│ ├─gvfs-gphoto2-vo───2*[{gvfs-gphoto2-vo}]
│ ├─gvfs-mtp-volume───2*[{gvfs-mtp-volume}]
│ ├─gvfs-udisks2-vo───3*[{gvfs-udisks2-vo}]
│ ├─gvfsd─┬─gvfsd-trash───2*[{gvfsd-trash}]
│ │ └─2*[{gvfsd}]
│ ├─gvfsd-fuse───5*[{gvfsd-fuse}]
│ ├─gvfsd-metadata───2*[{gvfsd-metadata}]
│ ├─ibus-portal───2*[{ibus-portal}]
│ ├─ibus-x11───2*[{ibus-x11}]
│ ├─pulseaudio───3*[{pulseaudio}]
│ ├─snap-store───4*[{snap-store}]
│ ├─tracker-miner-f───4*[{tracker-miner-f}]
│ ├─vmtoolsd───3*[{vmtoolsd}]
│ ├─xdg-desktop-por───5*[{xdg-desktop-por}]
│ ├─xdg-desktop-por───3*[{xdg-desktop-por}]
│ ├─xdg-document-po───6*[{xdg-document-po}]
│ └─xdg-permission-───2*[{xdg-permission-}]
├─systemd-journal
├─systemd-logind
├─systemd-network
├─systemd-resolve
├─systemd-timesyn───{systemd-timesyn}
├─systemd-udevd
├─udisksd───4*[{udisksd}]
├─unattended-upgr───{unattended-upgr}
├─upowerd───2*[{upowerd}]
├─vmhgfs-fuse───8*[{vmhgfs-fuse}]
├─vmtoolsd───3*[{vmtoolsd}]
├─vmware-vmblock-───3*[{vmware-vmblock-}]
├─whoopsie───2*[{whoopsie}]
└─wpa_supplicant
gec@ubuntu:~$
由上图可知,最开始的系统进程叫systemd(CentOS7之后,systemd取代init,也就是1号进程,更早的进程是idle,0号进程)。
init进程由idle通过kernel_thread创建,在内核空间完成初始化后,加载init程序,进入最终用户空间,然后启动其他系统进程。在系统启动完成后,init将变成为守护进程监视系统其他进程。
(这里不详细讲,在另外一篇博客讲)。
三、进程的状态
1、所有进程(除了系统初始进程systemd之外)都有一个父进程。
2、父进程通过调用fork()函数,将自身复制一份形成一个子进程。
3、新创建的子进程拥有与父进程一样的执行代码、内存空间(父子进程的内存空间的内容是一致的,但分属不同的区域各自独立)等信息,并处于就绪态(TASK_RUNNING)。
4、当进程退出时(不管是主动退出还是被动退出),进入僵尸态(EXIT_ZOMBIE),僵尸态下的进程无法运行,也无法被调度,但其所占据的系统资源未被释放。僵尸态是进程的必经状态,编程过程中不可能避免僵尸态,但要避免进程长时间处于僵尸态。
5、僵尸态进程要等待其父进程对其资源进程回收后,才能变成死亡态(EXIT_DEAD),死亡态的进程所占据的系统资源可以被系统随时回收。