【问题标题】:How can I Shell have more than one job in Linux我如何在 Linux 中拥有一份以上的工作
【发布时间】:2023-03-30 19:55:02
【问题描述】:

我是 Linux 初学者,只是有一些关于作业和进程组的问题。

我的教科书说'Unix shell 使用作业的抽象来表示由于评估单个命令行而创建的进程。在任何时间点,最多有一个前台作业和零个或多个后台作业。

假设我们有这个简单的 shell 代码(我省略了一些不重要的代码,即设置 argv 等):

当我们输入第一个commnad时,例如:./exampleProgram &

Q1- 是否创建了工作?如果是,该作业包含哪些流程?

shellex.c的main()被调用,所以在执行第15行时:fork()创建一个新的子进程,假设父进程是p1,新创建的子进程是c1 如果是后台作业,那么我们可以在提示符中输入另一个命令,./anotherProgram & 并输入回车

Q2- 我很确定它现在只是 p1 和 c1 并且 p1 正在执行第二个命令,当它再次执行第 15 行:fork() 时, 我们有 p1、c1 和新创建的 c2,我的理解是否正确?

Q3- 有多少工作?它只是一个包含 p1、c1 和 c2 的作业吗?

Q4-如果它只有一个作业,那么当我们不断输入新命令时,我们将只有一个作业包含一个父进程 p1 和许多子进程 c1、c2、c3、c4... 那么为什么我的教科书说壳牌可以有不止一份工作呢?以及为什么最多有一个前台作业和零个或多个后台作业。

【问题讨论】:

    标签: linux exception process linux-kernel


    【解决方案1】:

    关于这个话题有很多话要说,其中一些可以作为答案,其中大部分需要进一步阅读。

    对于Q1,我会在概念上说是的,但工作不是自动的,工作跟踪和控制也不是神奇的。我在您展示的代码片段中看不到任何逻辑,例如建立和维护工作表。我知道这只是一个示例,因此作业控制逻辑可能在其他地方。作业控制是常见的现有 Unix shell 的一项功能,但如果一个人从头开始编写新的 Unix shell,则需要添加作业控制功能,如代码/逻辑。

    对于Q2,你说的不是我说的。在第一次调用fork() 之后,是的,有一个 p1 和一个 c1,但首先要认识到 p1 和 c1 是 same 程序的不同实例(shellex);只有在调用execve() 之后,exampleProgram 才会运行。 fork() 创建shellex 的子实例,execve() 导致shellex 的子实例被exampleProgram 替换(在RAM 中)(假设这是argv[0] 的值)。

    没有真正意义上的父母正在“执行”孩子,也没有在execve()上替换孩子的过程,只是为了让他们继续前进。父启动子进程并可能等待子进程完成,但实际上父进程及其整个子进程层次结构都在各自执行,正在执行由内核。

    但是是的,如果被告知要运行的程序应该在后台运行,那么shellex 将接受进一步的输入,并且在下一次调用fork() 时,将有父shellex 和两个孩子过程。同样,起初子 c2 将是 shellex 的一个实例,很快就会通过 execve() 被任何已命名的程序替换。

    (关于在后台运行,&是否有这种效果取决于示例代码中名为parseline()的函数内部的逻辑。我熟悉的Shell使用&说“运行这个在后台”,但这并没有什么特别或神奇的地方。一个新编写的 Unix shell 可以用其他方式来完成它,尾随 +,或前导 BG:,或者 shell 作者决定做的任何事情.

    对于 Q3Q4,首先要识别的是您调用的父级 p1 您调用的 shell 程序'已经显示。所以,不,p1 不会参与这项工作。

    在 Unix 中,作业是作为单个管道的一部分执行的进程的集合。因此,一项作业可以由一个或多个进程组成。此类进程仍然连接到运行它们的终端,但可能处于前台(运行和交互)、挂起或后台(运行,非交互)。

    one process, foreground    : ls -lR
    one process, background    : ls -lR &
    one process, background    : ls -lR, then CTRL-Z, then bg
    many processes, foreground : ls -lR | grep perl | sed 's/^.*\.//'
    many processes, background : ls -lR | grep perl | sed 's/^.*\.//' &
    

    要凭经验查看作业与进程,请在后台运行管道(上面 5 个示例中的第 5 个),并在运行时使用 ps 向您显示进程 ID 和进程组 ID。例如,在我的 Mac 版本的 bash 上,是:

    $ ls -lR | grep perl | sed 's/^.*\.//' &
    [1] 2454                     <-- job 1, PID of the sed is 2454
    
    $ ps -o command,pid,pgid
    COMMAND         PID  PGID
    vim            2450  2450    <-- running in a different tab
    ls -lR         2452  2452    }
    grep perl      2453  2452    }-- 3 PIDs, 1 PGID
    sed s/^.*\.//  2454  2452    }
    

    与对 shell 和终端的这种连接不同,守护程序从两者分离。启动守护进程时,父进程使用fork() 启动子进程,但随后退出,只留下子进程运行,现在父进程的PID 为1。子进程关闭stdinstdout 和@ 987654356@,因为那些是没有意义的,因为守护进程“无头”运行。

    但在 shell 中,父进程——同样是 shell——要么保持运行 wait()ing(前台子程序),要么不运行 wait()ing(后台子程序),而孩子通常保留对stdinstdoutstderr 的使用(尽管这些可能被重定向到文件等)

    而且,一个shell 可以调用子shell,当然任何运行的程序都可以fork() 它自己的子进程,等等。因此,流程的层次结构可以变得非常深。如果没有其他特定操作,子进程将与其父进程位于同一进程组中。

    这里有一些文章供进一步阅读:

    What is difference between a job and a process in Unix?

    https://unix.stackexchange.com/questions/4214/what-is-the-difference-between-a-job-and-a-process

    https://unix.stackexchange.com/questions/363126/why-is-process-not-part-of-expected-process-group

    Bash Reference Manual; Job Control

    Bash Reference Manual; Job Control Basics

    【讨论】:

    【解决方案2】:

    作业不是 Linux 的东西,它不是后台进程,它是 您的特定 shell 定义为“作业”的东西。

    通常,shell 会引入“作业”的概念来进行作业控制。这通常包括一种识别作业并对其执行操作的方法,例如

    • 进入前台
    • 进入后台
    • 停止
    • 简历
    • 杀死

    如果一个 shell 没有办法做这些,那么谈论工作就没有什么意义了。

    【讨论】:

      猜你喜欢
      • 2017-05-23
      • 2018-07-28
      • 2013-08-14
      • 2021-01-03
      • 1970-01-01
      • 2019-07-04
      • 1970-01-01
      • 2017-03-13
      • 1970-01-01
      相关资源
      最近更新 更多