Files
Linux-C-Notes/C15-进程/C15-进程.md
2024-06-23 17:45:58 +08:00

280 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 目录
- [目录](#目录)
- [进程基本知识](#进程基本知识)
- [进程标识符`pid`](#进程标识符pid)
- [进程的产生](#进程的产生)
- [进程的消亡及释放资源](#进程的消亡及释放资源)
- [`exec`函数族](#exec函数族)
- [用户权限及组权限](#用户权限及组权限)
- [观摩课:解释器文件](#观摩课解释器文件)
- [`system()`函数](#system函数)
- [进程会计](#进程会计)
- [进程时间](#进程时间)
- [守护进程](#守护进程)
- [系统日志](#系统日志)
# 进程基本知识
已经进入**多进程**阶段
## 进程标识符`pid`
类型`pid_t`传统意义上是一个16位有符号整型数。
命令`ps`
常用命令:`ps axf``ps aux``ps axm``ps ax -L`
进程号是顺次向下使用
```c
// 返回当前进程号
pid_t getpid(void);
// 返回父进程的进程号
pid_t getppid(void);
```
## 进程的产生
`pid_t fork();`
- 以**复制duplicating**当前进程的方式创建一个新进程
-`setjmp`一样,执行一次,返回两次
-`fork`处复制,不会从头运行
`fork`后父子进程的不同之处:
1. `fork`的返回值不一样
2. `pid`不同
3. `ppid`也不同
4. 未决信号和文件锁不继承
5. 资源利用量清0
`init`进程:**1号**,是所有进程的祖先进程
调度器的调度策略来决定哪个进程先执行
`fflush()`的重要性
```c
/*
* vfork创建的子进程只能做exec或者exit
* ! 基本废弃
*/
pid_t vfork(void);
```
## 进程的消亡及释放资源
```c
// 等待进程状态发生变化
pid_t wait(int *status); // 阻塞
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
wait3();
wait4();
```
分配法和交叉分配法90%优先选择交叉分配法。
池类算法:
上游往池子里放任务,下游三个线程从池子里取任务。
## `exec`函数族
eg. `bash`进程创建`primer`进程
```c
// exec函数族替换当前进程的映像
extern char **environ;
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[]);
```
## 用户权限及组权限
`u+s`:如果文件是可执行的,则执行文件时,是以文件的拥有者的权限执行的。
```bash
-rwsr-xr-x 1 root root 68248 Mar 23 2023 /usr/bin/passwd
```
所以普通用户执行`passwd`时,是以`root`的权限执行的。
`g+s`:如果文件是可执行的,则执行文件时,是以文件的所在组的权限执行的。
`uid``gid`都有三种类型:
1. `real uid`:进程的实际所有者
2. `effective uid`:进程的有效所有者
3. `saved uid`:进程的保存的有效所有者
```
shell获取身份的流程
fork exec fork
init -->--> getty -->--> login -->--> shell
exec exec
root root root user
```
```c
// 获取当前用户的real uid
uid_t getuid(void);
// 获取当前用户的effective uid
uid_t geteuid(void);
// 获取当前进程的real gid
pid_t getegid(void);
// 获取当前进程的effective gid
pid_t getgid(void);
// 设置当前进程的real uid
int setuid(uid_t uid);
// 设置当前进程的effective uid
int seteuid(uid_t uid);
// 设置当前进程的real gid
int setgid(gid_t gid);
// 设置当前进程的effective gid
int setegid(gid_t gid);
// 交换uid和gid (原子操作)
int setreuid(uid_t ruid, uid_t euid);
// 交换gid和egid (原子操作)
int setregid(gid_t rgid, gid_t egid);
```
## 观摩课:解释器文件
> unix讲究机制而非策略
脚本,后缀名是什么都可以,一般用`sh`, `exec`
```bash
#!/bin/cat
# some shell
```
`#!`是一种约定俗成的标记,告诉系统这个脚本应该用什么解释器来执行。
## `system()`函数
```c
/*
* 运行一个shell命令
* 调用/bin/sh
*/
int system(const char *command);
```
相当于`fork+exec+wait`的封装
## 进程会计
```c
//! freeBSD系统的方言
int acct(const char *filename);
```
## 进程时间
```c
clock_t times(struct tms *buf);
// clock_t 滴答数
struct tms{
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
}
```
## 守护进程
1. 守护进程`PPID`为1
2. 守护进程没有控制终端,`TTY`为?
3. `PID, PGID, SID`相同
```c
pid_t setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); //! 方言
pid_t getpgrp(psid_t pid); //! 方言
```
- 会话session一个或多个进程组的集合`sid`为标识
`pid_t setsid(void);`
`setsid`必须由非`leader`进程调用,从而创建一个新的会话。
- 前台进程组:正在与终端交互的进程组
- 后台进程组:正在运行,但不与终端交互的进程组
- 终端:
我们接触的都是虚拟终端
**单实例守护进程**:锁文件`/var/run/name.pid`
启动脚本文件:`/etc/rc*...`
## 系统日志
`syslogd`服务
```c
#include <syslog.h>
/**
* 打开系统日志
*
* @prarm: ident 标识符
* @prarm: option 选项 LOG_CONS, LOG_NDELAY, LOG_NOWAIT, LOG_PERROR ...
* @prarm: facility 来源 LOG_USER, LOG_DAEMON, LOG_KERN, LOG_LOCAL0~7 ...
*/
void openlog(const char *ident, int option, int facility);
/**
* 记录系统日志
*
* @prarm: priority 优先级 以 ERR 与 WARNING 为分界点
* @prarm: format 格式化字符串
* @prarm: ... 格式化参数
*/
void syslog(int priority, const char *format, ...);
/**
* 关闭系统日志
*/
void closelog(void);
```
```bash
sudo tail /var/log/messages # 老师
journalctl -r # 我的debian
```