进程处理是操作系统中的一个核心概念,它涉及到进程的创建、调度、执行、通信、终止以及资源管理等多个方面。
一、进程的定义与特性
定义:进程是程序的一次执行过程,是系统进行资源分配和调度的一个独立单元。它是动态范畴的概念,与静态的程序不同。
特性:进程具有独立性、动态性、并发性、异步性、结构特征等。每个进程都有自己独立的内存空间和系统资源。
二、代码示例
常用处理参数说明。使用时,多注意僵尸进程和孤儿进程。手动创建手动回收。
processes.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define PATH ("/usr/bin/ping")
#define WEBSITE ("www.just1n.cn")
int main(int argc, char **argv)
{
// 使用标准库函数创建子进程
/**
* system (const char *__command)
* const char * __command:使用Linux命令直接创建
* return:成功返回0, 失败返回失败编号
*/
int res_sys = system("ping -c 30 www.baidu.com");
if(res_sys)
{
perror("system");
exit(EXIT_FAILURE);
}
// 调用 fock 之前,代码都在父进程中运行
// 子进程开始前
printf("__This is a parent process__\n");
int subProcess_status;
// 使用 fock 创建子进程
/**
* 不需要传参
* return: int 进程号
* (1):-1 出错
* (2): 父进程中表示子进程的PID
* (3): 子进程中显示为 0
*/
pid_t pid = fork();
// 从fork之后 所有的代码都是在父子进程中各自执行一次的
if (pid < 0)
{
perror("fork error");
exit(EXIT_FAILURE);
} else if (pid == 0)
{
// 子进程
char *args[] = {PATH, "-c", "10", WEBSITE, NULL};
char *envs[] = {NULL};
printf("__Accessing the website__PID_%d_\n", getpid());
// 执行跳转 : 跳转前后只有进程号保留了下来,别的变量都删除了
/**
* int execve (const char *__path, char *const __argv[], char *const __envp[])
* const char *__path:执行程序的路径
* char *const __argv[]:传入的参数 --> 对应执行程序main方法的第二个参数
* (1).第一个参数固定是程序的名称 --> 执行程序的路径
* (2).执行程序需要传入的参数
* (3).最后一个参数一定是NULL
* char *const __envp[]:传递的环境变量:
* (1).环境变量参数 => key=value
* (2).最后一个参数一定是NULL
* return:成功根本没办法返回,下面的代码也没有意义。失败返回 -1
*/
int res_exe = execve(args[0], args, envs);
if(res_exe < 0)
{
perror("execve");
exit(EXIT_FAILURE);
}
} else
{
// 父进程
printf("__parent process: %d__ waiting __child process: %d__\n", getpid(), pid);
waitpid(pid, &subProcess_status, 0);
}
printf("waiting is ok!\n");
}
Makefile
CC := gcc
processes : processes.c
- $(CC) -o $@ $^ # 编译
-./$@ # 运行
-rm ./$@ # 删除
后续
这里是学习中遇到的或想到的问题,以下都是个人总结。
2024-08-31
问题:既然所有的代码都在父子进程中各自执行一次,那为什么子进程close后父进程还能写入数据?
回答:和文件描述符中引用计数(f_count
)有关, 当有文件被引用时文件描述会+1,关闭则会-1,只有当f_count = 0
时才会真正的关闭文件(释放)。