《UNIX环境高级编程(第3版)》——1.6 程序和进程

简介: 通常,一个进程只有一个控制线程(thread)——某一时刻执行的一组机器指令。对于某些问题,如果有多个控制线程分别作用于它的不同部分,那么解决起来就容易得多。另外,多个控制线程也可以充分利用多处理器系统的并行能力。

本节书摘来自异步社区《UNIX环境高级编程(第3版)》一书中的第1章,第1.6节,作者:【美】W. Richard Stevens , Stephen A.Rago著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.6 程序和进程

1.程序

程序(program)是一个存储在磁盘上某个目录中的可执行文件。内核使用exec函数(7个exec函数之一),将程序读入内存,并执行程序。8.10节将说明这些exec函数。

2.进程和进程ID
程序的执行实例被称为进程(process)。本书的每一页几乎都会使用这一术语。某些操作系统用任务(task)表示正在被执行的程序。

UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一个非负整数。

实例
图1-6程序用于打印进程ID。

#include "apue.h"

int
main(void) 
{
   printf("hello world from process ID %ld\n", (long)getpid());
   exit(0); 
}

图1-6 打印进程ID

如果将该程序编译成a.out文件,然后执行它,则有:

$ ./a.out
hello world from process ID 851
$ ./a.out
hello world from process ID 854

此程序运行时,它调用函数getpid得到其进程ID。我们将会在后面看到,getpid返回一个pid_t数据类型。我们不知道它的大小,仅知道的是标准会保证它能保存在一个长整型中。因为我们必须在printf函数中指定需要打印的每一个变量的大小,所以我们必须把它的值强制转换为它可能会用到的最大的数据类型(这里是长整型)。虽然大多数进程ID可以用整型表示,但用长整型可以提高可移植性。

3.进程控制
有3个用于进程控制的主要函数:fork、exec和waitpid。(exec函数有7种变体,但经常把它们统称为exec函数。)

实例

UNIX系统的进程控制功能可以用一个简单的程序说明(见图1-7)。该程序从标准输入读取命令,然后执行这些命令。它类似于shell程序的基本实施部分。

#include "apue.h"
#include <sys/wait.h>

int
main(void) 
{
   char  buf[MAXLINE];  /* from apue.h */
   pid_t  pid; 
   int   status; 

   printf("%% ");  /* print prompt (printf requires %% to print %) */
   while (fgets(buf, MAXLINE, stdin) != NULL) {
     if (buf[strlen(buf) - 1] == '\n') 
        buf[strlen(buf) - 1] = 0; /* replace newline with null */

     if ((pid = fork()) < 0) {
        err_sys("fork error");
     } else if (pid == 0) {    /* child */
        execlp(buf, buf, (char *)0); 
        err_ret("couldn't execute: %s", buf); 
        exit(127); 
     }

     /* parent */
     if ((pid = waitpid(pid, &status, 0)) < 0) 
        err_sys("waitpid error");
     printf("%% ");
   }
   exit(0); 
}

图1-7 从标准输入读命令并执行

在这个30行的程序中,有很多功能需要考虑。

用标准I/O函数fgets从标准输入一次读取一行。当键入文件结束符(通常是Ctrl+D)作为行的第一个字符时,fgets返回一个null指针,于是循环停止,进程也就终止。第18章将说明所有特殊的终端字符(文件结束、退格字符、整行擦除等),以及如何改变它们。

因为fgets返回的每一行都以换行符终止,后随一个null字节,因此用标准C函数strlen计算此字符串的长度,然后用一个null字节替换换行符。这样做是因为execlp函数要求的参数是以null结束的而不是以换行符结束的。

调用fork创建一个新进程。新进程是调用进程的一个副本,我们称调用进程为父进程,新创建的进程为子进程。fork对父进程返回新的子进程的进程ID(一个非负整数),对子进程则返回0。因为fork创建一个新进程,所以说它被调用一次(由父进程),但返回两次(分别在父进程中和在子进程中)。

在子进程中,调用execlp以执行从标准输入读入的命令。这就用新的程序文件替换了子进程原先执行的程序文件。fork和跟随其后的exec两者的组合就是某些操作系统所称的产生(spawn)一个新进程。在UNIX系统中,这两部分分离成两个独立的函数。第8章将对这些函数进行更多说明。
子进程调用execlp执行新程序文件,而父进程希望等待子进程终止,这是通过调用waitpid实现的,其参数指定要等待的进程(即pid参数是子进程ID)。waitpid函数返回子进程的终止状态(status变量)。在我们这个简单的程序中,没有使用该值。如果需要,可以用此值准确地判定子进程是如何终止的。

该程序的最主要限制是不能向所执行的命令传递参数。例如不能指定要列出目录项的目录名,只能对工作目录执行ls命令。为了传递参数,先要分析输入行,然后用某种约定把参数分开(可能使用空格或制表符),再将分隔后的各个参数传递给execlp函数。尽管如此,此程序仍可用来说明UNIX系统的进程控制功能。

如果运行此程序,将得到下列结果。注意,该程序使用了一个不同的提示符(%),以区别于shell的提示符。

$ ./a.out
% date
Sat Jan 21 19:42:07 EST 2012
% who
sar       console   Jan 1  14:59
sar       ttys000   Jan 1  14:59
sar       ttys001   Jan 15 15:28
% pwd
/home/sar/bk/apue/3e
% ls
Makefile
a.out
shell1.c
% ^D                                    键入文件结束符
$                                       常规的shell提示符

^D表示一个控制字符。控制字符是特殊字符,其构成方法是:在键盘上按下控制键——通常被标记为Control或Ctrl,同时按另一个键。Ctrl+D或^D是默认的文件结束符。在第18章中讨论终端I/O时,会介绍更多的控制字符。

4.线程和线程ID
通常,一个进程只有一个控制线程(thread)——某一时刻执行的一组机器指令。对于某些问题,如果有多个控制线程分别作用于它的不同部分,那么解决起来就容易得多。另外,多个控制线程也可以充分利用多处理器系统的并行能力。

一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。

与进程相同,线程也用ID标识。但是,线程ID只在它所属的进程内起作用。一个进程中的线程ID在另一个进程中没有意义。当在一进程中对某个特定线程进行处理时,我们可以使用该线程的ID引用它。

控制线程的函数与控制进程的函数类似,但另有一套。线程模型是在进程模型建立很久之后才被引入到UNIX系统中的,然而这两种模型之间存在复杂的交互,在第12章中,我们会对此进行说明。

相关文章
|
2月前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
64 0
|
2月前
|
缓存 负载均衡 安全
在Python中,如何使用多线程或多进程来提高程序的性能?
【2月更文挑战第17天】【2月更文挑战第50篇】在Python中,如何使用多线程或多进程来提高程序的性能?
|
4月前
|
Windows
windows环境下根据端口号查询进程编号并杀掉此进程
windows环境下根据端口号查询进程编号并杀掉此进程
|
5月前
|
负载均衡 JavaScript 算法
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
44 1
|
9天前
|
Java Shell Linux
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
|
2月前
|
Shell Linux 调度
【Linux】—— 进程程序替换
【Linux】—— 进程程序替换
|
2月前
|
Java Linux Shell
进程的程序替换(exec函数)【Linux】
进程的程序替换(exec函数)【Linux】
|
3月前
|
监控 Unix Linux
socket监控进程,并对程序执行有关操作。
socket监控进程,并对程序执行有关操作。
|
4月前
|
Linux
Linux——进程程序替换
Linux——进程程序替换
|
4月前
|
Linux Shell
Linux进程程序替换
Linux进程程序替换
Linux进程程序替换