乐趣区

关于linux:Linux系统编程训练营3初试-Linux-进程

问题:strace 输入中的 execve(…)到底是什么?

过程实践状态切换

过程生命周期

Linux 过程基本概念

  • 过程是 Linux 工作的执行单元,也是 Linux 系统资源的调配单位
  • 每个 Linux 利用程序运行后由一个或多个过程
  • 一个 Linux 过程能够执行一个或多个程序
  • Linux 过程有多种不同状态(即:Linux 过程有不同的活法)

Linux 过程状态分析

  • 就绪 / 运行 状态 (R) : TASK_RUNNING
  • 阻塞状态:

    • 可中断 (S) : TASK_INTERRUPTIBLE(可被内核信号唤醒)
    • 不可中断 (D) : TASK_UNINTERRUPTIBLE(对实时性要求高时应用)
  • 进行状态 (T) : TASK_STOP
  • 退出状态:TASK_DEAD

    • 僵尸 (X) : EXIT_ZIMBIE(过程生命期完结,但内核中还保留着与过程相干的数据信息)
    • 死亡 (Z) : EXIT_DEAD
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0
   4826 pts/0    Ss     0:00 /bin/bash
   5328 pts/0    R+     0:00 ps ax
   5329 pts/0    S+     0:00 grep --color=auto pts/0
tiansong@tiansong:~/Desktop/linux$ sleep 120
^C【CTRL + C】
tiansong@tiansong:~/Desktop/linux$ sleep 120 &
[1] 5423
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0
   4826 pts/0    Ss     0:00 /bin/bash
   5423 pts/0    S      0:00 sleep 120
   5453 pts/0    R+     0:00 ps ax
   5454 pts/0    S+     0:00 grep --color=auto pts/0
tiansong@tiansong:~/Desktop/linux$ kill 5423
[1]+  Terminated              sleep 120
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0
   4826 pts/0    Ss     0:00 /bin/bash
   5501 pts/0    R+     0:00 ps ax
   5502 pts/0    R+     0:00 grep --color=auto pts/0

loop.c

int main()
{while(1);

    return 0;
}
tiansong@tiansong:~/Desktop/linux$ gcc ./loop.c -o loop.out
tiansong@tiansong:~/Desktop/linux$ ./loop.out &
[1] 6510
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/3
   6021 pts/3    Ss     0:00 /bin/bash
   6510 pts/3    R      0:04 ./loop.out
   6522 pts/3    R+     0:00 ps ax
   6523 pts/3    S+     0:00 grep --color=auto pts/3
tiansong@tiansong:~/Desktop/linux$ kill 6510
[1]+  Terminated              ./loop.out
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/3
   6021 pts/3    Ss     0:00 /bin/bash
   6543 pts/3    R+     0:00 ps ax
   6544 pts/3    S+     0:00 grep --color=auto pts/3

Linux 过程树简介

Linux 过程必知必会

  • 每个过程都有一个惟一的标识符(PID)
  • 每个过程都是由一个过程创立而来(即:父过程)
#include <sys/types.h>
#include <unistd.h>

pid_t getpid();    // 以后过程 id 
pid_t getppid();   // 以后过程父过程 id

一些乏味的问题

  • 问题一:第 1 个过程时什么?
  • 问题二:如何创立过程

Linux 过程树

  • 整个 Linux 零碎的所有过程形成一个树结构
  • 树根由内核主动创立,即:IDLE (PID → 0)
  • 零碎中的第一个过程是 init / systemd (PID → 1)

    • 0 号过程创立 1 号过程,1 号过程负责实现内核局部初始化工作
    • 1 号过程加载执行初始化程序,演变为用户态 1 号过程
tiansong@tiansong:~/Desktop/linux$ pstree
systemd-+-ModemManager---2*[{ModemManager}]
        |-NetworkManager---2*[{NetworkManager}]
        |-VGAuthService
        |-accounts-daemon---2*[{accounts-daemon}]
        |-acpid
        |-avahi-daemon---avahi-daemon
        |-bluetoothd
        |-colord---2*[{colord}]
        |-cron
        |-cups-browsed---2*[{cups-browsed}]
        |-cupsd---dbus
        |-dbus-daemon
        |-fwupd---4*[{fwupd}]
        |-gdm3-+-gdm-session-wor-+-gdm-x-session-+-Xorg---{Xorg}
        |      |                 |               |-gnome-session-b-+-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
        |-nmbd
        |-polkitd---2*[{polkitd}]
        |-rsyslogd---3*[{rsyslogd}]
        |-rtkit-daemon---2*[{rtkit-daemon}]
        |-sh---node-+-node-+-bash
        |           |      `-11*[{node}]
        |           |-node---11*[{node}]
        |           |-node---12*[{node}]
        |           `-10*[{node}]
        |-smbd-+-cleanupd
        |      |-samba-bgqd
        |      `-smbd-notifyd
        |-snapd---17*[{snapd}]
        |-sshd---sshd---sshd---bash---sleep
        |-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---10*[{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-dconf---3*[{ibus-dconf}]
        |         |             |             |-ibus-engine-sim---2*[{ibus-engine-sim}]
        |         |             |             |-ibus-extension----3*[{ibus-extension-}]
        |         |             |             `-2*[{ibus-daemon}]
        |         |             `-11*[{gnome-shell}]
        |         |-gnome-shell-cal---5*[{gnome-shell-cal}]
        |         |-gnome-terminal--+-bash---pstree
        |         |                 `-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}]
        |         |-tracker-miner-f---4*[{tracker-miner-f}]
        |         `-xdg-permission----2*[{xdg-permission-}]
        |-systemd-journal
        |-systemd-logind
        |-systemd-resolve
        |-systemd-timesyn---{systemd-timesyn}
        |-systemd-udevd
        |-udisksd---4*[{udisksd}]
        |-unattended-upgr---{unattended-upgr}
        |-upowerd---2*[{upowerd}]
        |-vmtoolsd---3*[{vmtoolsd}]
        |-whoopsie---2*[{whoopsie}]
        `-wpa_supplicant
// 打印以后过程 PID
tiansong@tiansong:~/Desktop/linux$ echo $$
6021
// 打印从树根到以后过程的门路,systemd(1091) 再次被加载实现更多初始化工作
tiansong@tiansong:~/Desktop/linux$ pstree -A -p -s $$
systemd(1)---systemd(1091)---gnome-terminal-(6837)---bash(6845)---pstree(7046)
tiansong@tiansong:~/Desktop/linux$ ./loop.out &
[1] 7214
tiansong@tiansong:~/Desktop/linux$ ./loop.out &
[2] 7217
tiansong@tiansong:~/Desktop/linux$ ./loop.out &
[3] 7220
tiansong@tiansong:~/Desktop/linux$ ./loop.out &
[4] 7223
tiansong@tiansong:~/Desktop/linux$ pstree -A -p -s $$
systemd(1)---systemd(1091)---gnome-terminal-(6837)---bash(6845)-+-loop.out(7254)
                                                                |-loop.out(7255)
                                                                |-loop.out(7256)
                                                                |-loop.out(7257)
                                                                `-pstree(7259)

Linux 过程创立实战

Linux 过程创立

  • pid_t fork(void);

    • (零碎调用)通过以后过程创立新过程,以后过程为父过程,新过程为子过程
  • int execve(const char *pathname, char *const argv[], char *const envp[]);

    • (零碎调用)在以后过程中执行 pathname 指定的程序代码

fork() 的工作形式

  • 为子过程申请内存空间,并将父过程数据齐全复制到子过程空间
  • 两个过程中的程序执行地位完全一致(fork()函数调用地位
  • 不同之处:

    • 父过程:fork() 返回紫禁城 PID
    • 子过程:fork() 返回 0
通过 fork() 返回值判断父子过程,执行不同代码

上面程序输入什么?为什么?

main.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

static int g_global = 0;

int main()
{
    int pid = 0;

    printf("Hello Word!\n");
    printf("current = %d\n", getpid());

    if ((pid = fork()) > 0) {
        g_global = 1;

        usleep(100);
        printf("child = %d\n", pid);
        printf("%d g_global = %d\n", getpid(), g_global);
    } 
    else {
        g_global = 10;
        printf("parent = %d\n", getppid());
        printf("%d g_global = %d\n", getpid(), g_global);
    }

    return 0;
}
tiansong@tiansong:~/Desktop/linux$ ./main.out 
Hello Word!
current = 8010
child = 8011
parent = 8010
8011 g_global = 10
8010 g_global = 1

fork 与 execve 利用

思考:如何了解“每个 Linux 过程能够执行一个或多个程序”?

1、过程是一个存在于内存的实体
2、过程由程序加载而来
3、过程能够加载多个程序的代码

execve (…) 的工作形式

  • 依据参数门路加载可程序程序(程序加载到以后过程中)
  • 通过可执行程序信息构建过程数据,并写入以后过程空间
  • 将程序执行地位重置到入口地址处(即:main())
  • execve(...) 重置以后过程空间(代码 & 数据)而不会创立新过程

上面的程序输入什么?为什么?

test.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#define EXE "helloword.out"

int main()
{char *args[] = {EXE, NULL};

    printf("begin\n");

    printf("pid = %d\n", getpid());

    execve(EXE, args, NULL);

    printf("end\n");

    return 0;
}

helloword.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{   
    printf("exec = %d, %s\n",
            getpid(), "Hello World!");

    return 0;
}
tiansong@tiansong:~/Desktop/linux$ gcc test.c -o test.out
tiansong@tiansong:~/Desktop/linux$ gcc helloword.c -o helloword.out
tiansong@tiansong:~/Desktop/linux$ ./test.out 
begin
pid = 8518
exec = 8518, Hello World!

留神:end 没有输入


test.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#define EXE "helloword.out"

int create_process(const char *path, char *args[])
{int ret = fork();

    if (ret == 0) {execve(path, args, NULL);
    }

    return ret;
}

int main()
{char *args[] = {EXE, NULL};

    printf("begin\n");

    printf("pid = %d\n", getpid());

    printf("child = %d\n", create_process(EXE, args));

    printf("end\n");

    return 0;
}
tiansong@tiansong:~/Desktop/linux$ ./test.out 
begin
pid = 8833
child = 8834
end
exec = 8834, Hello World!
退出移动版