0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux进程控制简介与要素及相关函数详解

GReq_mcu168 来源:CSDN技术社区 作者:码农爱学习 2021-04-03 10:52 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

Linux进程简介

进程是操作系统中的一个重要概念,它是一个程序的一次执行过程,程序是进程的一种静态描述,系统中运行的每一个程序都是在它的进程中运行的。

进程4要素

要有一段程序供该进程运行

进程专用的系统堆栈空间

进程控制块(PCB),具体实现是task_struct结构

有独立的存储空间

Linux系统中所有的进程是相互联系的,除了初始化进程外,所有进程都有一个父进程。新的进程不是被创建,而是被复制,或是从以前的进程复制而来。Linux中所有的进程都是由一个进程号为1的init进程衍生而来的。

Linux系统包括3种不同类型的进程,每种进程都有自己的特点和属性:

交互进程:由一个Shell启动的进程,既可以在前台运行,又可以在后台运行

批处理进程:这种进程和终端没有联系,是一个进程序列

监控进程(守护进程):Linux启动时启动的进程,并在后台运行

进程控制块

在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(PCB, Process Control Block),描述进程的运动变化过程,与进程是一一对应的关系。通常PCB包含以下信息:

进程标识符:每个进程的唯一标识符,可以是字符串,也可以是数字。

进程当前状态:为方便管理,相同状态的进程会组成一个队列,如就绪进程队列。

进程相应的程序和数据地址:以便把PCB与其程序和数据联系起来。

进程资源清单:列出所有除CPU外的资源记录,如拥有的I/O设备,打开的文件列表等。

进程优先级:反映进程的紧迫程度,通常由用户指定和系统设置。

CPU现场保护区:当进程因某种原因不能继续占用CPU时,释放CPU,需要将CPU的各种状态信息保护起来。

进程同步与通信机制:用于实现进程间互斥、同步和通信所需的信号量等。

进程所在队列PCB的链接字:根据进程所处的现行状态,进程相应的PCB参加到不同队列中,PCB链接字指出该进程所在队列中下一进程PCB的首地址。

与进程有关的其它信息:如进程记账信息,进程占用CPU的时间等。

通过ps命令可以查看系统中目前有多少进程正常运行

通过ps-aux命令可以查看每个进程的详细信息

进程控制的相关函数

fork()函数

系统调用fork()函数派生一个进程,函数原型为:

#include 《sys/types.h》

#include 《unistd.h》

pid_t fork(void);

运行成功,父进程返回子进程ID,子进程饭0;运行出错返回-1。

fork系统调用的作用是复制一个进程,从而出现两个几乎一样的进程。一般来说,fork后是父进程先执行还是子进程先执行是不确定的,取决于内核所实使用的调度算法

fork函数示例,fork_test.c:

#include 《sys/types.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

int count = 0;

pid_t pid;

pid = fork();

if(pid 《 0)

{

printf(“error in fork!”);

exit(1);

}

else if(pid == 0)

printf(“I am the child process, the count is %d, my process ID is%d

”, count, getpid());

else

printf(“I am the parent process, the count is %d, my process ID is%d

”, ++count, getpid());

return 0;

}

编译后运行:

$ 。/fork_test

I am the parent process, the count is 1, my process ID is2308

I am the child process, the count is 0, my process ID is2309

在语句pid = fork();之前,只有一个进程在执行代码,但在该语句之后,有两个进程在执行之后的代码,根据pid的不同执行不同的语句。

fork调用的神奇之处在于被调用一次,能够返回两次,返回结果可能有3种情况:

父进程中:fork返回新创建的子进程的ID

子进程中:fork返回0

出现错误:fork返回负值

fork出错的原因有2:

当前进程数已达系统规定的上限,此时errno的值被设置为EAGAIN

系统内存不足,此时errno的值被设置为ENOMEN

errno是Linux下的一个宏定义常量,当Linux中C API函数发生异常时,一般会将errno变量赋值为一个正整数(需include),不同的值表示不同的含义,通过查看该值可推测出错原因。

vfork()函数

vfork()与fork()的区别是:fork()需要复制父进程的数据段,而vfork()不需要完全复制,在子进程调用exec()或exit()之前,子进程与父进程共享数据段。fork()不对父子进程的执行次序作限制,而vfork()调用后,子进程先运行,父进程挂起,直到子进程调用了exec()或exit()后,父子进程的执行次序才不再有限制。

实际上,vfork()创建出的不是真正意义的进程,它缺少了进程4要素的最后一项——独立的内存资源。

vfork()创建父子进程共享数据段测试,vfork_test1.c():

#include 《sys/types.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

int count = 1;

int child;

printf(“Before create son, the father‘s count is:%d

”, count);

child = vfork();

if(child 《 0)

{

printf(“error in vfork!”);

exit(1);

}

if(child == 0)

{

printf(“This is son, his pid is:%d and the count is:%d

”, getpid(),++ count);

exit(1);

}

else

printf(“After son, This is father, his pid is:%d and the count is:%d, and the child is:%d

”, getpid(), count, child);

return 0;

}

编译后运行:

$ 。/vfork_test1

Before create son, the father’s count is:1

This is son, his pid is:2530 and the count is:2

After son, This is father, his pid is:2529 and the count is:2, and the child is:2530

可以看出,在子进程中修改了count的值,变为2,而父进程中count值也为2,说明父子进程共享count,即父子进程共享内存区。

vfork()创建子进程导致父进程挂起测试,vfork_test2():

#include 《sys/types.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

int count = 1;

int child;

printf(“Before create son, the father‘s count is:%d

”, count);

if(!(child = vfork()))

{

int i;

for(i=0; i《100; i++)

{

printf(“This is son, the i is:%d

”, i);

if(i == 70)

exit(1);

}

printf(“This is son, his pid is:%d and the count is:%d

”, getpid(), ++count);

exit(1);

}

else

printf(“After son, This is father, his pid is:%d and the count is:%d, and the child is:%d

”, getpid(), count, child);

return 0;

}

编译后运行:

$ 。/vfork_test2

Before create son, the father’s count is:1

This is son, the i is:0

This is son, the i is:1

This is son, the i is:2

。..省略

This is son, the i is:67

This is son, the i is:68

This is son, the i is:69

This is son, the i is:70

After son, This is father, his pid is:2541 and the count is:1, and the child is:2542

可以看出,父进程是等待子进程执行完毕后才开始执行。

exec函数族

Linux使用exec函数族来执行新的程序,以新的子进程来完全代替原有的进程,exec函数族包含6个函数:

#include 《unistd.h》

int execl(const char *pathname, const char *arg, 。..);

int execlp(const char *filename, const char *arg, 。..);

int execle(const char *pathname, const char *arg, 。.., char *const envp[]);

int execv(const char *pathname, char *const argv[]);

int execvp(const char *filename, char *const argv[]);

int execve(const char *pathname, char *const argv[], char *const envp[]);

运行成功无返回,出错返回-1。

函数中含义字母l的:其参数个数不定,参数由命令行参数列表组成,最v后一个NULL表示结束。

函数中含义字母v的:使用一个字符串数组指针argv指向参数列表,与含字母l的函数参数列表完全相同。

函数中含义字母p的:可以自动在环境变量PATH指定的路径中搜索要执行的程序,其第一参数filename为可执行函数的文件名,注意其它函数的第一个参数pathname为路径名

函数中含义字母e的:比其它函数多了一个字符串指针型的envp参数,用于指定环境变量。

实际上,只有execve()函数才是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。与一般情况不同,exec函数族执行成功后不会返回,因为调用进程实体,包括代码段、数据段和堆栈段都被新的内容取代,只是进程ID等一些表面上的信息仍保持原样。

exec函数族使用举例,exec_example.c:

#include 《unistd.h》

#include 《stdio.h》

int main(void)

{

char *envp[] = {“PATH=/tmp”, “USER=root”, “STATUS=testing”, NULL};

char *argv_execv[] = {“echo”, “excuted by execv”, NULL};

char *argv_execvp[] = {“echo”, “excuted by execvp”, NULL};

char *argv_execve[] = {“env”, NULL};

if(fork()==0)

{

if(execl(“/bin/echo”, “echo”, “executed by execl”, NULL))

perror(“Err on execl”);

}

if(fork()==0)

{

if(execlp(“echo”, “echo”, “executed by execlp”, NULL))

perror(“Err on execlp”);

}

if(fork()==0)

{

if(execle(“/usr/bin/env”, “env”, NULL, envp))

perror(“Err on execle”);

}

if(fork()==0)

{

if(execv(“/bin/echo”, argv_execv))

perror(“Err on execv”);

}

if(fork()==0)

{

if(execvp(“echo”, argv_execvp))

perror(“Err on execvp”);

}

if(fork()==0)

{

if(execve(“/usr/bin/env”, argv_execve, envp))

perror(“Err on execve”);

}

return 0;

}

上述程序用到了perror()函数,它用来将函数发生错误的原因输出到标准输出(stderr),其函数原型为:

《pre class=“lang_c”》#include 《stdio.h》

void perror(const char *s)

```

编译后执行:

$ 。/exec_example

PATH=/tmp

USER=root

STATUS=testing

executed by execl

executed by execlp

$ PATH=/tmp

USER=root

STATUS=testing

excuted by execvp

excuted by execv

由于各子进程执行的顺序无法控制,因而每次运行结果的输出顺序会有不同。

使用exec函数族,一般要加上错误判断语句,因为exec函数易由多种原因运行失败:

找不到文件或路径:errno被设置为ENOENT

数组argv和envp忘记使用NULL结束:errno被设置为EFAULT

没有文件的运行权限:errno被设置为EACCES

exit()与_exit()函数

这两个函数都是用于终止进程,其定义分别为:

#include 《stdlib.h》

void exit(int status);

#include 《unistd.h》

void _exit(int status);

两者主要区别在于:

定义及所需头文件不同

_exit()立即进入内核;exit()则先执行一些清除处理(包括调用执行个终止处理程序,关闭所有标准I/O流等),然后进入内核。

exit()在调用之前要检查文件的打开情况,把文件缓冲区的内容写回文件;_exit()则直接使进程停止,清除其使用的内存空间,并销毁其在内核中的各种数据结构。

在Linux的标准函数库中,有一套被称为“高级I/O的函数”,如printf()、fopen()等,也被称为“缓冲I/O(buffered I/O)”,其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次会多读出若干条记录,当达到一定的条件(如达到一定数量,或遇到特定字符,如‘ ’和文件结束符EOF)时,再将缓冲区的内容一次性写入文件,从而增加读写速度。但是,这种情况下,如果使用_exit()退出,会导致某些数据未被保存,而用exit()则不会有问题。

exit()与_exit()函数的区别测试,exit_differ.c:

#include 《sys/types.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

pid_t pid;

if((pid=fork()) == -1)

{

printf(“failed to create a new process

”);

exit(0);

}

else if(pid == 0)

{

printf(“

child process, output begin

”);

printf(“child process, content in buffer”);

_exit(0);

}

else

{

printf(“parent process, output begin

”);

printf(“parent process, content in buffer”);

exit(0);

}

return 0;

}

编译后执行:

$ 。/exit_differ

parent process, output begin

parent process, content in buffer

child process, output begin

由于printf函数遇到’ ‘时才从缓冲区读取数据,在子进程中,因为_exit(0)直接将缓冲区的内容清除了,内容没有显示;而父进程中,执行exit(0)之前会先将缓冲区的内容显示出来。

wait()与waitpid()函数

在一个进程调用了exit()之后,该进程并非立即消失,而是留下一个僵尸进程(Zombie)的数据结构,这时的一种处理方法就是使用wait()和waitpid()函数。

僵尸态是进程的一种特殊状态,没有任何可执行代码,也不能被调度,仅仅在进程中保留一个位置,记载改进程的退出状态等信息供其它进程收集。

wait()和waitpid()函数原型:

#include 《sys/types.h》

#include 《sys/wait.h》

pid_t wait(int *status);

pid_t waitpid(pid_t, int *status, int options);

运行成功返回进程ID,出错返回-1。

参数status用于保存进程退出时的一些状态,如果只是想把进程灭掉,可以设置该参数为NULL。

参数pid用于指定所等待的线程。

pid取值含义

pid 》 0只等待进程ID为pid的子线程

pid = -1等待任何一个子线程,此时waitpid等价于wait

pid = 0等待同一个进程组中的任何子进程

pid 《 -1等待一个指定进程组中的任何子进程,其进程ID为pid的绝对值

参数options提供一些额外的选项来控制waitpid,包括WNOHANG和WUNTRACED两个选项,这是两个常数,可以用|运算符连接使用。其中WNOHANG参数用于设置不等待子进程退出,立即返回,此时waitpid返回0;WUNTRACED参数用于配置跟踪调试。

进程一旦调用wait后,就立刻阻塞自己,如果当前进程的某个子进程已退出,则收集其信息,否则wait会一种阻塞在这里,直到有一个僵死进程出现。

wait()示例

wait_example.c:

#include 《sys/types.h》

#include 《sys/wait.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

pid_t pc, pr;

if((pc = fork()) 《 0)

{

printf(“error in fork!”);

exit(1);

}

else if(pc == 0)

{

printf(“This is child process with pid of %d

”, getpid());

sleep(10);

}

else

{

pr = wait(NULL);

printf(“I catched a child process with pid of %d

”, pr);

}

exit(0);

}

编译后执行:

$ 。/wait_example

This is child process with pid of 10093

I catched a child process with pid of 10093

可以看到,第1行输出后,等待大约10秒,第2行才输出,这10秒就是子线程的睡眠时间。

waitpid()示例

父进程和子进程分别睡眠10秒钟和1秒钟,代表所作的相应工作。父进程利用工作的简短间歇查看子进程是否退出,如果退出就收集它。waitpid_example.c:

#include 《sys/types.h》

#include 《sys/wait.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

pid_t pc, pr;

if((pc = fork()) == -1)

{

printf(“failed to create a new process”);

exit(0);

}

else if(pc == 0)

{

sleep(10);

exit(0);

}

do

{

pr = waitpid(pc, NULL, WNOHANG);

if(pr == 0)

{

printf(“No chiled exited

”);

sleep(1);

}

}while(pr == 0);

if(pr == pc)

printf(“successfully get child %d

”, pr);

else

printf(“some error occured

”);

return 0;

}

sdfgh

$ 。/waitpid_example

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

No chiled exited

successfully get child 2711

可以看到,父进程经过10次失败尝试后,终于收集到了退出的子进程。

获取子进程返回状态

对于wait()和waitpid()中的status参数,当其值不为NULL时,子进程的退出状态会以int值的形式保存其中,通过一套专门的宏(macro)可以读取存入的状态值,这里只列举两个常用的宏:

宏定义含义

WIFEXITED(status)子进程正常退出时,返回一个非零值,否则返回零

WEXITSTATUS(status)当WIFEXITED为真时,此宏才可用,返回该进程退出的代码

示例,子进程调用exit(3)退出,WIFEXITED(status)指示子进程正常退出,WEXITSTATUS(status)就会返回3。get_status.c:

#include 《sys/types.h》

#include 《sys/wait.h》

#include 《stdio.h》

#include 《stdlib.h》

#include 《unistd.h》

int main(void)

{

int status;

pid_t pc, pr;

if((pc = fork()) 《 0)

{

printf(“error in fork!”);

exit(1);

}

else if(pc == 0)

{

printf(“This is child process with pid of %d.

”, getpid());

exit(3);

}

else

{

pr = wait(&status);

if(WIFEXITED(status))

{

printf(“the child process %d exit normally.

”, pr);

printf(“the return code is %d.

”, WEXITSTATUS(status));

}

else

printf(“the child process %d exit abnormally.

”, pr);

}

return 0;

}

assvf

$ 。/get_status

This is child process with pid of 2718.

the child process 2718 exit normally.

the return code is 3.

可以看出,父进程捕捉到了子进程的返回值3。

system()函数

函数原型:

#include 《stdlib.h》

int system(const char *cmdstring);

sysytem()调用fork()产生子进程,由子进程来调用/bin/sh-cmdstring来执行参数cmdstring字符串所代表的命令,此命令执行完后随即返回原调用的进程。

编程示例,4次调用system,设置不同的命令行参数,system返回不同的结果,cmd_system.c:

#include 《stdio.h》

#include 《stdlib.h》

int main(void)

{

int status;

if((status = system(NULL)) 《 0)

{

printf(“system error!

”);

exit(0);

}

printf(“exit status=%d

”, status);

if((status = system(“date”)) 《 0)

{

printf(“system error!

”);

exit(0);

}

printf(“exit status=%d

”, status);

if((status = system(“invalidcommand”)) 《 0)

{

printf(“system error!

”);

exit(0);

}

printf(“exit status=%d

”, status);

if((status = system(“who; exit 44”)) 《 0)

{

printf(“system error!

”);

exit(0);

}

printf(“exit status=%d

”, status);

return 0;

}

adss

$ 。/cmd_system

exit status=1

2019年 12月 10日 星期二 1436 CST

exit status=0

sh: 1: invalidcommand: not found

exit status=32512

deeplearning pts/0 2019-12-10 13:46 (192.168.1.110)

exit status=11264

第1次调用system,参数为NULL,返回结果为1,说明在本Linux系统下system可用;第2次调用system,参数为data,system成功执行;第3次调用system,参数为一个非法的字符串命令,返回结果shell的终止状态(命令出错)32512;第4次调用system,参数为who,显示登录用户情况,exit 44是退出当前的shell,system成功返回,返回值11264。

参考:《精通Linux C编程》- 程国钢
编辑:lyn

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11817

    浏览量

    219534
  • 函数
    +关注

    关注

    3

    文章

    4421

    浏览量

    67832
  • 编译
    +关注

    关注

    0

    文章

    696

    浏览量

    35279

原文标题:Linux进程控制

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    飞凌嵌入式ElfBoard-进程相关信息之用户ID和组ID

    Linux操作系统中,用户ID(UID) 和 组ID(GID)对进程有着重要的作用,主要影响到进程的权限管理、资源访问以及操作系统的安全性。进程的用户ID和组ID代表了该
    发表于 03-12 17:13

    飞凌嵌入式ElfBoard-进程相关信息之父进程和子进程

    进程在创建时,创建进程是新进程的父进程,新进程是创建进程的子
    发表于 03-12 17:12

    飞凌嵌入式ElfBoard-进程之什么是进程

    ;当程序运行时,操作系统会为其分配一个唯一的进程标识符(PID);通过getpid() 函数获取该进程的 PID;最后将 PID 打印到标准输出(通常是终端或控制台)。
    发表于 03-02 08:49

    Linux进程管理不用愁!这6个工具帮你搞定90%场景

    Linux 系统中,进程是资源分配的基本单位,无论是服务器运维、程序调试还是日常使用,掌握进程管理工具都是必备技能。今天就带大家梳理 6 个最常用的进程管理工具,从查看
    的头像 发表于 02-04 16:23 2810次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>进程</b>管理不用愁!这6个工具帮你搞定90%场景

    Linux进程树分析工具pstree详解与实战指南(另一视角优化Linux系统)

    Linux 系统开发与运维中,理解进程的运行状态和相互关系是排查问题、优化性能的基础。pstree 作为一款轻量高效的进程树可视化工具,能直观展示系统中所有进程的父子关系,为系统分
    的头像 发表于 02-04 16:21 895次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>进程</b>树分析工具pstree<b class='flag-5'>详解</b>与实战指南(另一视角优化<b class='flag-5'>Linux</b>系统)

    飞凌嵌入式ElfBoard-进程之什么是进程

    的开始和结束在 Linux 操作系统中,程序是静态的可执行文件,而进程是动态的实体。从程序变为进程的过程涉及多个步骤,其中还包括系统资源的管理和初始化。1.当用户在 Shell 中输入命令时,Shell
    发表于 01-26 08:42

    进程概念和特征

    的并发性和共享性。   为了使参与并发执行的程序(含数据)能独立地运行,必须为之配置一个专门的数据结构,称为进程控制块(Process Control Block, PCB)。系统利用PCB来描述
    发表于 01-15 06:39

    进程控制

    进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。在操作系统中,一般把
    发表于 01-15 06:05

    ElfBoard嵌入式教育科普|Linux系统I/O接口:Open函数详解

    1.函数概述open()是Linux/Unix内核提供的底层系统调用,核心功能是打开或创建文件。成功调用后,内核会返回一个整型的文件描述符作为该文件的句柄,后续的所有读写操作都基于此描述符进行。调用
    的头像 发表于 12-29 11:41 1280次阅读
    ElfBoard嵌入式教育科普|<b class='flag-5'>Linux</b>系统I/O接口:Open<b class='flag-5'>函数</b><b class='flag-5'>详解</b>

    深入Linux内核:进程调度的核心逻辑与实现细节

    Linux系统中,进程调度就像一位精明的“CPU管理员”——它决定着哪个进程能优先使用CPU,多久切换一次进程,如何平衡系统响应速度与资源利用率。小到桌面应用的流畅点击,大到服务器的
    的头像 发表于 12-24 07:05 4576次阅读
    深入<b class='flag-5'>Linux</b>内核:<b class='flag-5'>进程</b>调度的核心逻辑与实现细节

    解析Linux进程、线程和协程

    影响其他进程进程之间是高度隔离的。Linux中,进程进程标识符(PID)唯一标识。 进程
    发表于 12-22 11:00

    Linux进程间通信(IPC)全解析:从管道到 Socket,一篇讲透

    在 Linux 世界里,进程并非孤立存在。无论是后台服务协作(如 Web 服务器与数据库)、命令行工具联动(如ps | grep),还是复杂应用的模块通信,都离不开 进程间通信(IPC
    的头像 发表于 11-14 21:38 1.3w次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>进程</b>间通信(IPC)全解析:从管道到 Socket,一篇讲透

    详解Linux权限相关指令

    Linux严格来说是一个操作系统,我们称之为“核心”(kernel)。而作为用户的我们并不能直接与核心交流,这时候就有一个中间人的角色出现:将我们的指令翻译为核心可以看懂的符号,交由核心执行,并将执行结果翻译并返回给我们。
    的头像 发表于 06-06 11:47 1069次阅读
    <b class='flag-5'>详解</b><b class='flag-5'>Linux</b>权限<b class='flag-5'>相关</b>指令

    详解Linux系统中的服务管理

    Linux中,无论何时当你安装任何带有服务和守护进程的包,系统默认会把这些服务的初始化及 systemd脚本添加进去,不过此时它们并没有被启用。
    的头像 发表于 05-23 15:10 936次阅读
    <b class='flag-5'>详解</b><b class='flag-5'>Linux</b>系统中的服务管理

    Linux后台进程管理详解

    当我们在终端或控制台工作时,可能不希望由于运行一个作业而占住了屏幕,因为可能还有更重要的事情要做,比如阅读电子邮件。对于密集访问磁盘的进程,我们更希望它能够在每天的非负荷高峰时间段运行(例如凌晨)。为了使这些进程能够在后台运行,
    的头像 发表于 04-25 11:04 1155次阅读
    <b class='flag-5'>Linux</b>后台<b class='flag-5'>进程</b>管理<b class='flag-5'>详解</b>