嵌入式成长轨迹19 【Linux应用编程强化】【Linux下的C编程 下】【进程操作】
详细概念和原理之后见 嵌入式成长轨迹27 进程管理
【基本知识】
计算机中:
堆 静态 全局 malloc
栈 子函数临时变量 局部变量
Linux系统是一个多进程的系统,进程之间具有并行性、互不干扰的特点。
linux中进程包含3个段,分别为“代码段”、“数据段”和“堆栈段”。
“数据段”存放全局变量、常数以及动态数据分配的空间(malloc函数取得的空间);
“代码段”存放程序代码;
“堆栈段”存放子程序的返回地址、子程序的参数以及程序的局部变量。
每个linux进程都一定有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一非负整数
进程ID为1通常是init进程,在自举过程结束时由内核调用。init进程绝不会终止。它是一个普通的用户进程(与交换进程不同,它不是内核中的系统进程),但是它以超级用户特权运行
一 进程的概念
进程(Process)是指操作系统中被加载到内存中的、正在运行的应用程序实例。它最初是随着批处理系统和分时系统的出现而引入的,因为在这些系统中,有多个并发执行的程序,仍然使用程序这个静态的概念已经无法描述系统中程序动态变化的过程了。
1 进程的组成
进程主要由程序、数据以及进程控制块(PCB)3个部分组成
1).程序
2).数据
3).进程控制块
2 进程的状态
在多任务系统中,进程在CPU上交替运行,状态不断改变
二 Linux进程
Linux系统中,每个进程由一个task_struct数据结构来描述,即前面提到的进程控制块PCB。task_struct包含了进程管理和控制的所有信息,它的定义在头文件linux/sched.h之中。
1 进程的状态
Linux系统中的进程主要有如下几种状态:
1).运行状态
2).等待状态
3).暂停状态
4).僵死状态
2 进程调度信息
task_struct结构中包含了进程调度相关的信息,调度程序利用这些信息来判定系统中哪个进程最迫切需要运行,并结合进程的状态等信息以保证系统运转的公平和高效。这部分信息主要包括进程的类别、进程的优先级以及进程的调度策略等。
3 进程的标识符
用户标识符(UID)和组标识符(GID)
有效用户标识符(EUID)和有效组标识符(EGID)
文件系统用户标识符(FSUID)和文件系统组标识符(FSGID)
备份用户标识符(SUID)和备份组标识符(SGID)
4 进程间通信相关信息
多个进程之间要协调进行以完成一项任务时,必须通过进程间的通信来实现数据的交换。Linux支持多种不同形式的通信机制,既支持典型的Unix通信机制,例如信号(Signals)、管道(Pipes),也支持System V通信机制,如共享内存(Shared Memory)、信号量和消息队列(Message Queues)
5 进程链接信息
Linux系统中,所有进程都是相互关联的,没有哪个进程是独立运行的。除了系统的初始化进程外,所有进程都有一个父进程。从某种意义上讲,Linux系统中的新进程并不是被创建的,而是被复制的,即新进行是其父进程的一个克隆版本。每个进程的task_struct结构都包含有指向其父进程、兄弟进程以及子进程的指针。
6 时间和定时器信息
一个进程从创建到终止称为该进程的生存期。进程的创建时间以及在其生存期内消耗的CPU时间,内核都需要进行跟踪记录。进程耗费的CPU时间由两部分组成:一是在用户模式(或称为用户态)下耗费的时间,二是在系统模式(或称为系统态)下耗费的时间。实时定时器(ITIMER_REAL)虚拟定时器(ITIMER_VIRTUAL)
Profile定时器(ITIMER_PROF)
7 文件系统信息
进程可以打开或关闭文件,文件属于系统资源,Linux内核需要对进程使用文件的情况进行记录。task_struct结构中使用了两个成员来描述进程所使用的文件系统相关信息,即fs_struct和files_struct。
8 其他信息
task_struct结构是进程存在的惟一标志,系统内核通过该结构来实现进程的各种操作。除了上面介绍的内容外,task_struct结构中还包含虚拟内存信息、页面管理信息、对称多处理器(SMP)信息以及上下文信息等,这里就不再逐一介绍。
三 进程创建与控制
Linux系统下用于新进程创建的函数主要有4个:fork函数、vfork函数、system函数以及popen函数。进程终止有多种方式,这里主要介绍exit函数和_exit函数。最后将介绍如何获取进程的相关信息。
1 fork函数
pid_t fork(void);
该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是子进程的进程ID。
一般来说,在f o r k之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。
父、子进程之间的区别是:
fork的返回值;
进程I D、不同的父进程I D;
子进程的t m s _ u t i m e , t m s _ s t i m e , t m s _ c u t i m e以及t m s _ u s t i m e设置为0;
父进程设置的锁,子进程不继承;
子进程的未决告警被清除;
子进程的未决信号集设置为空集。
fork函数复制当前进程的内容,产生一个新的进程,调用fork函数的进程称为父进程,所产生的新进程称为子进程。子进程会继承父进程的一切特性,但是它拥有自己的数据段。也就是说,尽管子进程改变了所属的变量,但不会影响到父进程的变量值。
1 /* example1.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 int main()
6 {
7 pid_t pid;
8 pid = fork(); /* 创建新的进程 */
9 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
10 {
11 printf("fork error.\n");
12 exit(1);
13 }
14 if(pid==0) /* 子进程 */
15 printf("This is the child process.\n");
16 else /* 父进程 */
17 printf("This is the parent process.\n");
18 return 0;
19 }
2 wait和waitpid函数
pid_t wait (int *status);
pid_t waitpid(pid_t pid, int * status, int options);
WNOHANG、WUNTRACED
wait函数用于使父进程阻塞,直到一个子进程结束或者该进程接收到一个指定信号为止
调用wait或waitpid的进程可能会:
阻塞(如果其所有子进程都还在运行)。
带子进程的终止状态立即返回(如果一个子进程已终止,正等待父进程存取其终止状态)。
出错立即返回(如果它没有任何子进程)。
wait和waitpid函数的区别:
在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。
waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
实际上wait函数是waitpid函数的一个特例。
waitpid函数提供了wait函数没有提供的三个功能:
(1) waitpid等待一个特定的进程(而w a i t则返回任一终止子进程的状态)。
(2) waitpid提供了一个w a i t的非阻塞版本。有时希望取得一个子进程的状态,但不想阻塞。
(3) waitpid支持作业控制(以WUNTRACED选择项)。
对于waitpid的p i d参数的解释与其值有关:
pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。
pid > 0 等待其进程I D与p i d相等的子进程。
pid == 0 等待其组I D等于调用进程的组I D的任一子进程。
pid < -1 等待其组I D等于p i d的绝对值的任一子进程。
子进程的结束状态值是一个整数,特定的位表示特定的信息。系统在sys/wait.h中定义了几个宏,用于对该值进行判别
WIFEXITED(status)
WEXITSTATUS(status)
WIFSIGNALED(status)
WTERMSIG(status)
WIFSTOPPED(status)
WSTOPSIG(status)
1 /* example2.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h> /* 注意包含该头文件 */
6 int main()
7 {
8 pid_t pid;
9 int status, i = -1;
10 pid = fork(); /* 创建新的进程 */
11 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
12 {
13 printf("fork error.\n");
14 exit(1);
15 }
16 if(pid==0) /* 子进程 */
17 {
18 printf("This is the child process.\n");
19 }
20 else /* 父进程 */
21 {
22 sleep(1);
23 printf("This is the parent process.\n");
24 printf("Waiting for child process ... \n");
25 if(pid != wait(&status)) /* 等待子进程结束 */
26 {
27 printf("wait error.\n");
28 exit(1);
29 }
30 if(~WIFEXITED(status)) /* 判断子进程是否为正常结束 */
31 {
32 i = WEXITSTATUS(status); /* 返回状态值 */
33 }
34 printf("child's pid = %d\n", pid); /* 输出子进程标识符 */
35 printf("exit status = %d\n", i); /* 输出子进程结束状态值 */
36 }
37 return 0;
38 }
1 /* example3.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 int x = 1;
7 void child_process() /* 子进程 */
8 {
9 printf("Child process %d, x = %d\n", getpid(), x);
10 x++;
11 printf("Child process %d, x = %d\n", getpid(), x);
12 }
13 int main()
14 {
15 pid_t pid;
16 int status;
17 pid = fork(); /* 创建新的进程 */
18 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
19 {
20 printf("fork error.\n");
21 exit(1);
22 }
23 if(pid==0) /* 子进程 */
24 {
25 child_process();
26 }
27 else /* 父进程 */
28 {
29 sleep(1);
30 printf("Parent process %d, x = %d\n", getpid(), x);
31 if(pid != wait(&status)) /* 等待子进程结束 */
32 {
33 printf("wait error.\n");
34 exit(1);
35 }
36 }
37 return 0;
38 }
1 /*waitpid.c*/
2 #include <sys/types.h>
3 #include <sys/wait.h>
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 int main()
9 {
10 pid_t pc,pr;
11 pc=fork();
12 if(pc<0)
13 printf("Error fork.\n");
14 else if(pc==0)
15 {
16 sleep(5);
17 exit(0);
18 }
19 else
20 {
21 do
22 {
23 pr=waitpid(pc,NULL,WNOHANG);
24 if(pr==0)
25 {
26 printf("The child process has not exited\n");
27 sleep(1);
28 }
29 }while(pr==0);
30
31 if(pr==pc)
32 printf("Get child %d\n",pr);
33 else
34 printf("some error occured.\n");
35 }
36 }
3 vfork函数和exec函数
vfork函数的作用类似于fork函数,使用vfork函数创建新进程的主要目的在于使用exec函数来执行别的程序,即启动一个新的应用程序。
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,
char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[],char *const envp[]);
1 /* example4.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 int main()
7 {
8 pid_t pid;
9 int status;
10 pid = vfork(); /* 使用vfork函数创建新进程 */
11 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
12 {
13 printf("vfork error.\n");
14 exit(1);
15 }
16 if(pid==0) /* 新进程 */
17 {
18 execlp("ps", "ps", "-o", "pid,ppid,comm", NULL); /* 调用execlp函数 */
19 }
20 else /* 父进程 */
21 {
22 if(pid != wait(&status)) /* 等待进程结束 */
23 {
24 printf("wait error.\n");
25 exit(1);
26 }
27 printf(" Done! \n");
28 }
29 return 0;
30 }
1 /* example5.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 int main()
7 {
8 pid_t pid;
9 int status;
10 char *arrArg[] = {"test", "A", "B", "C", NULL};
11 char *arrEnv[] = {"env1=100", "env2=yanyb", NULL};
12 pid = vfork(); /* 使用vfork函数创建新进程 */
13 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
14 {
15 printf("vfork error.\n");
16 exit(1);
17 }
18 if(pid==0) /* 新进程 */
19 {
20 execve ("./exe/test", arrArg, arrEnv); /* 调用上面的可执行文件test,输出各命令行参数和新的环境变量 */
21 }
22 else /* 父进程 */
23 {
24 if(pid != wait(&status)) /* 等待进程结束 */
25 {
26 printf("wait error.\n");
27 exit(1);
28 }
29 }
30 return 0;
31 }
4 system函数
system函数通过调用Shell程序/bin/sh来在新的进程中执行参数cmdstring所指定的命令。如果该函数调用成功,则返回值为0。
int system(const char * cmdstring)
1 /* example6.c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 int main()
5 {
6 system("ps -o pid,ppid,comm ");
7 return 0;
8 }
5 popen函数 标准流管道
popen函数类似于system函数,它是一种执行外部程序的简易方法。与system函数的不同之处在于它使用了管道的方式来启动新的进程。
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
使用popen()创建的管道必须使用pclose( )关闭。其实,popen/pclose和标准文件输入/输出流中的fopen() / fclose()十分相似。
1 /* example7.c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #define BUFSIZE 1024
5 int main()
6 {
7 char buf[BUFSIZE];
8 FILE *pp;
9 char *cmd = "ps -f";
10 if( (pp = popen(cmd, "r")) == NULL ) /* 将命令的输出通过管道读取到pp之中 */
11 {
12 printf("popen error!\n");
13 exit(1);
14 }
15 while(fgets(buf, sizeof(buf), pp)) /* 将pp中的数据流读取到缓冲区中 */
16 {
17 printf("%s", buf);
18 }
19 pclose(pp);
20 return 0;
21 }
6 进程终止
进程的终止主要有以下几种方式:在main函数中执行return语句。
调用exit函数。
调用_exit函数。忽视缓冲区.直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的数据结构;
exit与_exit函数不同,exit函数在调用exit系统之前要检查文件打开情况把文件缓冲区的内容写回文件中去。如调用printf()函数。
调用abort函数。收到能导致进程终止的信号。
1 /* example8.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 int main()
6 {
7 printf("Hello World.\n");
8 printf("ABC");
9 _exit(0);
10 }
1 /* example9.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 int main()
5 {
6 printf("Hello World.\n");
7 printf("ABC");
8 exit(0);
9 }
7 获取进程信息
结构体task_struct包含了一个进程的所有信息,可以通过函数来获取这些信息。在前面的程序中,我们已经使用了getpid函数来获取进程的标识符。
pid_t getpid(void)
pid_t getppid (void)
pid_t getpgid(pid_t pid)
pid_t getpgrp(void)
int getpriority(int which, int who)
PRIO_PROCESS、PRIO_PGRP或PRIO_USER
1 /* example10.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 int main()
7 {
8 pid_t pid;
9 int status;
10 pid = fork(); /* 创建新的进程 */
11 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
12 {
13 printf("fork error.\n");
14 exit(1);
15 }
16 if(pid==0) /* 子进程 */
17 {
18 printf("Child Process:\n");
19 printf("pid = %d\n", getpid()); /* 获取当前进程的标识符 */
20 printf("ppid = %d\n", getppid()); /* 获取父进程的标识符 */
21 printf("gid = %d\n", getpgrp()); /* 获取进程的组标识符 */
22 exit(1);
23 }
24 else /* 父进程 */
25 {
26
27 printf("Parent Process:\n");
28 printf("pid = %d\n", getpid()); /* 获取当前进程的标识符 */
29 printf("ppid = %d\n", getppid()); /* 获取父进程的标识符 */
30 printf("gid = %d\n", getpgrp()); /* 获取进程的组标识符 */
31 if(pid != wait(&status)) /* 等待进程结束 */
32 {
33 printf("wait error.\n");
34 exit(1);
35 }
36 }
37 return 0;
38 }
四 守护进程
守护进程(Daemon)是一种运行在后台,独立于所有终端控制之外的特殊进程。守护进程通常在系统引导时启动,在系统关闭时终止,它周期性地执行某种任务或等待处理某些发生的事件。
1 守护进程的创建方法
守护进程除了后台运行、自身的运行环境以及启动方式等一些特殊性外,与普通进程基本上没有什么区别。编写守护进程一般方法是把普通进程按照守护进程的特性进行改造。
1).将子进程放入后台运行
2).在子进程中创建新会话
pid_t setsid(void);3).关闭打开的文件描述符
4).改变工作目录
5).重设文件权限掩码
umask(0);
6).处理SIGCHLD信号
signal(SIGCHLD, SIG_IGN);
1 /* example11.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6 #define MAXFILE 1024
7 int main()
8 {
9 pid_t pid;
10 FILE *fp; /* 定义文件指针 */
11 int i;
12 char *buf = "This is a Dameon.\n";
13 pid = fork(); /* 创建新的进程 */
14 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
15 {
16 printf("fork error.\n");
17 exit(1);
18 }
19 if(pid>0) /* 终止父进程,使子进程进入后台运行 */
20 {
21 exit(0);
22 }
23 setsid(); /* 创建一个新的会话 */
24 for(i=0; i<MAXFILE; i++) /* 关闭打开的文件描述符 */
25 close(i);
26 chdir("/tmp"); /* 改变工作目录 */
27 umask(0); /* 重设文件权限掩码 */
28 signal(SIGCHLD, SIG_IGN); /* 处理SIGCHLD信号 */
29 while(1)
30 {
31 fp = fopen("/tmp/test", "a"); /* 打开文件 */
32 if(fp == NULL)
33 {
34 perror("Open test failed "); /* 如果文件打开失败,输出错误信息 */
35 exit(1);
36 }
37 fputs(buf, fp); /* 向文件写入字符串 */
38 fclose(fp); /* 关闭文件 */
39 sleep(1);
40 }
41 }
2 守护进程的输出
守护进程没有控制终端,需要提供专门的途径来处理从系统中获得的各种信息,因为既不能简单地写入标准输出之中,也不可能要求每一个守护进程将各自的信息写入一个单独的文件之中,这样不利于系统的管理与维护。Linux系统中,提供了一个syslogd守护进程,任何进程都可以通过syslog函数来记录各种事件。
void syslog(int priority, char *format, ...);
1 /* example12.c */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6 #include <syslog.h> /* 注意包含该头文件 */
7 #define MAXFILE 1024
8 int main()
9 {
10 pid_t pid;
11 int i;
12 time_t now;
13 pid = fork(); /* 创建新的进程 */
14 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */
15 {
16 printf("fork error.\n");
17 exit(1);
18 }
19 if(pid>0) /* 终止父进程,使子进程进入后台运行 */
20 {
21 exit(0);
22 }
23 setsid(); /* 创建一个新的会话 */
24 for(i=0; i<MAXFILE; i++) /* 关闭打开的文件描述符 */
25 close(i);
26 chdir("/"); /* 改变工作目录 */
27 umask(0); /* 重设文件权限掩码 */
28 signal(SIGCHLD, SIG_IGN); /* 处理SIGCHLD信号 */
29 syslog(LOG_USER|LOG_INFO, "Daemon test!\n"); /* 写入到/var/log/messages文件之中 */
30 while(1)
31 {
32 time(&now); /* 获取当前时间 */
33 syslog(LOG_USER|LOG_INFO, "Current time:\t%s\t\t\n", ctime(&now));
34 sleep(1);
35 }
36 }
3 守护进程的出错处理——syslog函数
由于守护进程完全脱离了控制终端,因此,不能像其他程序一样通过输出错误信息到控制台的方式来通知程序员。
通常的办法是使用syslog服务,将出错信息输入到“/var/log/message”系统日志文件中去。
Syslog是linux中的系统日志管理服务通过守护进程syslog来维护。
Openlog函数用于打开系统日志服务的一个连接;
Syslog函数用于向日志文件中写入消息,在这里可以规定消息的优先级、消息的输出格式等;
Closelog函数用于关闭系统日志服务的连接。
接下来看看syslog函数格式
(1)openlog函数
#include <syslog.h>
void openlog(char * ident, int option,int facility) ;
Ident:要向每个消息加入的字符串,通常为程序的名称;
option参数:
LOG_CONS: 若日志消息不能通过发送至syslogd ,则将该消息写至控制台;
LOG_NDELAY: 立即打开UNIX域数据报套接口至syslsgd守护进程。通常,在记录第一条消息之前,该套接口不打开。
LOG_PERROR:除将日志消息发送给syslog外,还将它写至标准出错(stderr)。
LOG_PID:每条消息都包含进程ID,此选择项可供对每个请求都fork一个子进程的守护进程使用。
openlog的facility参数
LOG_AUTH 授权程序: login.su,getty, ?
LOG_CRONcron 和 at
LOG_DAEMON 系统守护进程:ftpd,routed, ?
LOG_KERN 内核产生的消息
LOG_LOCAL0~7 保留由本地使用
LOG_LPR 行打系统:lpd, lpc, ?
LOG_MAIL 邮件系统
LOG_NEWSU senet网络新闻系统
LOG_SYSLOG syslogd守护进程本身
LOG_USER 来自其他用户进程的消息
LOG_UUCP UUCP系统
(2)syslog函数
#include <syslog.h>
void syslog(int priority, char *format, ...);
Priority选项(消息优先级)
LOG_EMERG 紧急(系统不可使用) (最高优先级)
LOG_ALERT 必须立即修复的条件
LOG_CRIT 临界条件(例如,硬设备出错)
LOG_ERR 出错条件
LOG_WARNING 警告条件
LOG_NOTICE 正常,但重要的条件
LOG_INFO 信息性消息
LOG_DEBUG 调试排错消息(最低优先级)
(3)closelog函数
#include <syslog.h>
void closelog(void);
syslog_dameon.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<fcntl.h>
5 #include<sys/types.h>
6 #include<unistd.h>
7 #include<sys/wait.h>
8 #include<syslog.h>
9
10 #define MAXFILE 65535
11 int main()
12 {
13 pid_t pc,sid;
14 int i,fd,len;
15 char *buf="This is a Dameon\n";
16 len =strlen(buf);
17 pc=fork();
18 if(pc<0)
19 {
20 printf("error fork\n");
21 exit(1);
22 }
23 else if(pc>0)
24 exit(0);
25 openlog("demo_update",LOG_PID, LOG_DAEMON);
26 if((sid=setsid())<0)
27 {
28 syslog(LOG_ERR, "%s\n", "setsid");
29 exit(1);
30 }
31 if((sid=chdir("/"))<0)
32 {
33 syslog(LOG_ERR, "%s\n", "chdir");
34 exit(1);
35 }
36 umask(0);
37 for(i=0;i<MAXFILE;i++)
38 close(i);
39 while(1)
40 {
41 if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND, 0600))<0)
42 {
43 syslog(LOG_ERR, "open");
44 exit(1);
45 }
46 write(fd, buf, len+1);
47 close(fd);
48 sleep(10);
49 }
50 closelog();
51 exit(0);
52 }
五 常见面试题
常见面试题1:Linux系统中的进程主要有几种状态?
常见面试题2:在Linux系统中如何创建守护进程?
六 小结
Linux是一个多用户、多任务的操作系统,进程管理是其内核中的一个重要组成部分。进程是程序在计算机系统上的一次执行活动,它不仅是系统内部独立运行的实体,还是资源竞争和分配的基本单位。理解进程的概念、掌握进程的创建、等待、终止等方法是这里及后续学习的基础,尤其是fork、exec、system以及wait等函数。
守护进程(Daemon)是运行在后台的一种特殊进程,它通常伴随着Linux系统始终运行。因此如果要把自己的进程改造成为守护进程,务必要小心操作,同时还要深刻理解进程之间的相互关系。