文件编程中的进程与多任务处理

一、进程的概念


1.进程的定义

进程是程序在内存中运行时的一个实例,是操作系统进行资源分配和调度的基本单位。例如,当我们运行一个程序(如 QQ)时,每次运行都会创建一个新的进程。即使运行的是同一个程序,每次创建的进程都是独立的。

例如,`main.c`是程序的源代码文件,而`a.out`是编译后的可执行程序。运行`a.out`的命令(如`./a.out`)会将程序加载到内存中,形成一个进程。


2.进程与程序的区别


• 程序:静态的代码和数据的集合,存储在磁盘上。

• 进程:动态的程序执行过程,运行在内存中。

例如:

• 程序:`main.c`(源代码文件)。

• 进程:编译后运行的`a.out`文件。


二、为什么需要进程?


1.历史背景


• 第一台计算机(ENIAC)一次只能运行一个程序。

• 随着 CPU 性能的提升,单片机和多核处理器的出现,计算机需要同时处理多个任务。


2.进程的作用


• 并发与并行:实现多个任务同时运行(并发)或同时执行(并行)。

• 资源管理:操作系统通过进程来管理计算机的软硬件资源。


三、进程的组成


1.程序的组成

程序由代码和数据组成,具体分为以下几个部分:

• 代码区(text):存放程序的指令。

• 数据区(data):存放已初始化的全局变量和静态变量。

• BSS 区(bss):存放未初始化的全局变量和静态变量。

• 堆(heap):动态分配的内存区域。

• 栈(stack):用于函数调用时的局部变量存储。


2.进程的组成

进程不仅包括程序的代码和数据,还包括进程控制块(PCB,Process Control Block)。


PCB 的内容

• PID(进程 ID):唯一标识一个进程。

• PPID(父进程 ID):标识父进程的 ID。

• 当前工作路径:进程的工作目录。

• 打开的文件列表:进程打开的文件描述符。

• 信号相关设置:处理异步事件的信号信息。

• 用户 ID 和组 ID:标识进程的用户和组。


四、进程的状态

进程的状态可以通过`ps`命令查看,常见的状态包括:


 状态      含义     
 R         运行态或可运行态     
 S         可中断睡眠态     
 D         不可中断睡眠态     
 T         暂停态     
 Z         僵尸态     
 X         已退出     

可以通过以下命令查看进程状态:

• `ps -aux`:查看系统中所有进程的详细信息。

• `ps -eLf`:查看系统中所有进程的线程信息。


五、进程管理的命令


1.`top`命令

类似于 Windows 的任务管理器,用于动态查看系统中进程的运行情况。可以实时显示系统的 CPU 使用率、内存使用率以及各进程的资源占用情况。


2.`ps`命令

用于查看当前系统中的进程信息。常用参数包括:

• `-e`:显示所有进程。

• `-f`:显示完整的进程信息。

• `-L`:显示所有线程。

• `-aux`:显示更详细的进程信息。

常用示例:

```bash
ps -eLf | head -1  # 查看进程信息的标题行
ps -eLf | grep a.out  # 查找包含 "a.out" 的进程
ps -aux | grep a.out  # 查找包含 "a.out" 的进程
```

3.`pstree`命令

用于查看进程的树状结构。可以清晰地展示进程之间的父子关系。常用参数包括:

• `-p`:显示进程 ID。

• `-sp`:显示进程的父进程 ID。

示例:

```bash
pstree -sp 5934  # 查看 PID 为 5934 的进程的树状结构
```

4.`kill`命令

用于向进程发送信号。常用的信号包括:

• `-9`:强制终止进程。

• `-15`(默认):向进程发送终止信号。

示例:

```bash
kill -9 5266  # 强制终止 PID 为 5266 的进程
kill -l  # 查看所有可用的信号
```

六、Linux 下的进程编程


1.创建进程:`fork()`

`fork()`是创建进程的核心函数,用于从当前进程中克隆一个子进程。


函数原型

```c
pid_t fork(void);
```

返回值

• 在父进程中:返回子进程的 PID(>0)。

• 在子进程中:返回 0。

• 失败时:返回-1,并设置`errno`。


示例代码

```c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();
    if (pid < 0) {
        perror("Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("This is the child process, PID: %d\n", getpid());
    } else {
        // 父进程
        printf("This is the parent process, PID: %d, Child PID: %d\n", getpid(), pid);
    }
    return 0;
}
```

2.进程的状态与关系


• 孤儿进程:父进程退出后,子进程仍然存在,由`init`进程(PID 为 1)收养。

• 僵尸进程:子进程退出后,父进程未回收子进程的资源,子进程进入僵尸态。


3.练习


练习 1
创建子进程,让父进程和子进程分别打印"hello"。


```c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();
    if (pid < 0) {
        perror("Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        while (1) {
            printf("Child: hello\n");
            sleep(1);
        }
    } else {
        // 父进程
        while (1) {
            printf("Parent: hello\n");
            sleep(1);
        }
    }
    return 0;
}
```

练习 2
通过`fork()`创建多个进程,验证父子进程的关系。


```c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    for (int i = 0; i < 5; i++) {
        pid_t pid = fork();
        if (pid < 0) {
            perror("Fork failed");
            return 1;
        } else if (pid == 0) {
            printf("Child process %d, PID: %d, Parent PID: %d\n", i, getpid(), getppid());
            break;
        }
    }
    if (getpid() == getppid()) {
        printf("Parent process, PID: %d\n", getpid());
    }
    return 0;
}
```

七、总结

进程是操作系统中非常重要的概念,通过`fork()`可以创建子进程,实现多任务并发处理。在实际开发中,进程编程广泛应用于服务器程序、多任务处理等领域。

希望本文对你理解进程的概念和使用有所帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值