Linux和Unix一样,有一个虚拟内存系统,能够把程序代码和数据以内存页面的形式放到硬盘的一个区域中,所以
Linux可以管理的进程比物理内存所能容纳的要多得多。
进程表
查看进程
ps -ef
TTY 一列显示了进程是从那个终端启动的。TIME一列是进程到目前为止所占用的CPU时间。
CMD一列显示启动进程使用的命令。STAT一列用来表明进程的当前代码。
STAT代码解释:
S
R
D
T
Z
N
W
s
+
l
<
#include<stdlib.h>
int system(const char *string);
system函数的作用是,运行以字符串参数的形式传递给它的命令并等待该命令的完成。命令的执行情况就如同在
shell中执行下列命令
$ sh -c string
1.替换进程映像
#include<unistd.h>
int execl(const char *path, const char *arg0 , ... , (char *)0);
int execlp(const char *file , const char *arg0, ... , (char *)0);
int execle(const char *path , const char *arg0 , ... , (char *)0 , char *const envp[] );
int execv(const char *path, const char *arg0 , ... , (char *)0);
int execvp(const char *file , const char *arg0, ... , (char *)0);
int execve(const char *path , const char *arg0 , ... , (char *)0 , char *const envp[] );
这些函数可以分为两类,execl,execlp和execle的参数个数是可变的,参数以一个空指针结构结束。
以字母P结尾的函数通过搜索path环境变量来查找程序的可执行文件的路径。
2.复制进程映像
#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);
子进程中的fork调用返回的是0,父子进程可以通过这一点来判断究竟谁是父进程,谁是子进程。
经过fork调用后,父进程返回一个新的进程PID,子进程返回0。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
char *message;
int n;
printf("fork program starting\n");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 5;
break;
default:
message = "This is the parent";
n = 3;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}
等待一个进程
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *stat_loc);
wait系统调用将父进程知道它的子进程结束为止。这个调用返回子进程的PID,它通常是已经结束运行的子进程的PID。
我们可以用sys/wait.h文件定义的宏来解释状态信息。如表11-2所示
宏 说明
WIFEXITED(stat_val) 如果子进程正常结束,它就取一个非零值。
WEXITSTATUC(stat_val) 如果WIFEXITED非零,它就返回子进程的退出码。
WIFSIGNALED(stat_val) 如果子进程因为一个未捕获的信号而终止,它就取一个非零值。
WTERMSIG(stat_val) 如果WIFSIGNALED非零,它返回一个信号代码。
WIFSTOPPED(stat_val) 如果子进程意外终止,它就取一个非零值。
WSTOPSIG(stat_val) 如果WIFSTOPPED非零,它返回一个信号代码
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
char *message;
int n;
int exit_code;
printf("fork program starting\n");
pid = fork();
switch(pid)
{
case -1:
exit(1);
case 0:
message = "This is the child";
n = 5;
exit_code = 37;
break;
default:
message = "This is the parent";
n = 3;
exit_code = 0;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
/* This section of the program waits for the child process to finish. */
if(pid) {
int stat_val;
pid_t child_pid;
child_pid = wait(&stat_val);
printf("Child has finished: PID = %d\n", child_pid);
if(WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else
printf("Child terminated abnormally\n");
}
exit (exit_code);
}
僵尸进程
用fork来创建进程确实很有用,但你必须清楚子进程的运行情况。子进程终止时,它与父进程之间的关联还会保持。
直到父进程也正常终止或父进程调用wait才告结束。因此,进程表中代表子进程的表项不会立刻释放。虽然子进程
已经不再运行,但它依然存在系统中,因为它的退出码还需要保存起来,以备父进程今后的wait调用使用。这时它
成为一个死进程或僵尸进程。
还有一个系统调用可以用来等待子进程的结束,它是waitpid函数。你可以用它来等待某个特定的进程结束。
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc , int options);
输入输出重定向
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int main()
{
int ch;
while((ch = getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}
/* This code, useupper.c, accepts a file name as an argument
and will respond with an error if called incorrectly. */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *filename;
if(argc != 2) {
fprintf(stderr, "usage: useupper file\n");
exit(1);
}
filename = argv[1];
/* That done, we reopen the standard input, again checking for any errors as we do so,
and then use execl to call upper. */
if(!freopen(filename, "r", stdin)) {
fprintf(stderr, "could not redirect stdin to file %s\n", filename);
exit(2);
}
execl("./upper", "upper", 0);
/* Don't forget that execl replaces the current process;
provided there is no error, the remaining lines are not executed. */
perror("could not exec ./upper");
exit(3);
}
freopen()函数负责把一个流重定向到另外一个流。