UC高级编程第三天

UC高级编程第三天

1.int fcntl(int fd, int cmd, … /* arg */ );
功能:
操作/控制文件描述符
参数:
fd: 要操作的文件描述符
cmd: 指定了对文件描述符操作的命令

	文件的状态信息:
	F_GETFL 
	F_SETFL
	
	建议锁的类型:
	F_GETLK  测试锁, 并不实际加锁, 如果可以加锁, 会在l_type中返回F_UNLCK
					 如果不能加锁, 在l_pid返回持有互斥锁进程PID
	F_SETLK  设置锁, 如果锁是互斥锁(写锁), 返回-1, errno被设置 EAGAIN EACCES
	F_SETLKW 设置锁, 如果锁是互斥锁, 等待其他进程释放锁
	
返回值:
	成功 0 
	错误 -1 errno被设置

一.对文件夹进行操作

1.使用库函数对文件夹进行操作

1.opendir(3)

DIR *opendir(const char *name);
	功能:打开一个文件夹
	参数: name, 指定了要打开的文件夹的名字
	返回值:成功 文件夹流
					错误 NULL errno被设置

2.closedir(3)

int closedir(DIR *dirp);
	功能:关闭文件夹流
	参数: dirp 文件夹流
	返回值:成功 0 
					错误 -1 errno被设置
	

3.readdir(3)

struct dirent *readdir(DIR *dirp); 
	功能:遍历文件夹流
	参数: 文件夹流
	返回值:
				成功 返回一个指向struct dirent指针  
						 NULL 读到了文件夹流的末尾
				错误 NULL 

4.glob(3)

int glob(const char *pattern,int flags,int(*errfunc)(const char *epath,int eerrno),glob_t *pglob);
功能:
		解析给定的模式, 模式的规则符合shell 
	参数:
		pattern:指定的模式 shell bash
		flags:  要求
		errfunnc: 错误处理函数
		pglob: 保存查找的/匹配的结果 		
	返回值:
		成功:0  结果保存到pglob
		错误:没匹配到  指定errfunc

二,linux中密码校验过程

1.密码存储在这里

/etc/shadow

2.使用crypt来加密密码

读出来的是加密之后的字符串, 和用户输入的密码加密之后的字段相匹配 

3.密码的键入

getpass(3) 

4.glob(3) 是一个用于匹配文件名模式(pattern)的函数,它遵循 shell 的规则来扩展文件名模式。

shell的规则:
1. ```
1. “/etc/" 表示/etc/下的所有文件
2. “/etc/a?” 表示/etc/所有以a开头的文件 ?通配
3. "/etc/
.c” 表示/etc下的所有.c文件

```

```
strsep(3) 
	char *strsep(char **stringp, const char *delim);
	功能:
		分割字符串
	参数:	
	**stringp 就是指向要分割的字符串
	*delim 由切割字符组成的字符串
	返回值:
		成功 返回切割出来的字符串
		错误 NULL 
```

三,并发

进程与程序的区别

程序存放在硬盘中, 是计算机指令的集合 是静态的
进程是运行着的程序, 程序运行的实例 是动态的

进程的基本状态

​ a. 就绪态

​ b.运行态

​ c. 阻塞态

​ d. 终止态

linux是采用时间片轮训

进程的状态

ps -aux//显示当前运行的进程列表

image-20240710122941126

ps -axj//显示进程的关系

image-20240710123057634

PPID:父进程的,PID 进程的,PGID 进程组的ID 会话的ID

ps axm -L///显示进程中的线程的状态

linux中c语言是如何终止的

1.从main函数中return //return到C启动例程中
调用exit(3)
调用__exit(3) 或_Exit(3)
调用pthread_exit(3)
最后一个线程从启动例程返回
调用abort
最后一个对取消请求做出响应
接受到signal终止进程

2.c程序的启动

内核调用C启动例程, C启动例程是系统已经写好的代码
C启动例程调用main函数, 从而整个进程就运行起来了

3.C程序的终止

main中return到C启动例程,

C启动例程调用exit(3)终止进程
main中调用exit(3)
main中调用_exit(2)
用户函数中调用exit(3)
用户函数中调用_exit(2)

exit(3)和_exit(2)的区别
exit(3)最终是要调用_exit(2)终止进程, _exit是系统调用 exit是库函数
exit(3)在调用_exit(2)之前, 先调用进程终止处理函数和标准IO清理程序 fclose
_exit(2) 什么都不做直接终止进程

4.进程的环境

用户级的进程
所有的用户级进程都是以树状的形式进行组织的
如何查看进程树:
pstree

image-20240710140948521

进程只有两种关系:
父子关系 兄弟关系

创建子进程:

进程只有两种关系:
		父子关系 兄弟关系

pid_t fork(void);
功能:
创建一个子进程
返回值:
成功:
在父进程中返回子进程的pid 子进程中返回0
错误:
在父进程中返回-1 errno被设置

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

int main() {
    pid_t pid = fork(); // 创建子进程

    if (pid < 0) {
        // fork失败
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("I am the child process. PID: %d\n", getpid());
    } else {
        // 父进程
        printf("I am the parent process. PID: %d, Child PID: %d\n", getpid(), pid);
    }

    return 0;
}
  • 子进程和父进程分别运行在自己独立的4G虚拟地址空间

  • fork并不是返回两次, 而是向父进程返回子进程的pid 向子进程返回0

在执行过程中父进程和子进程谁先执行不确定,跟内核的调度策略有关系

遗言函数:

int atexit(void (*function)(void))
返回值: 成功 0 
错误 非0值 
int on_exit(void (*function)(int, void *), void *arg)
参数:function 函数指针 
						arg  要传递给遗言函数的第二个参数, 第一个参数来自exit(status)
			返回值: 成功 0 
						错误 非0值

活着的时候不执行,死了才执行

获取环境变量

getenv (3) 
char *getenv(const char *name);
功能:
			获取环境变量 
		参数:	
			要查找的环境变量的名字 
		返回值:
			环境变量的value
			

设置环境变量

int setenv(const char *name, const char *value, int overwrite); 
		overwrite: 非0,可以修改成功环境变量的值
							 0
		name: 环境变量列表中不存在, 添加,环境变量列表中存在, 修改为value
		unsetenv(3) //从环境变量列表中移除一个环境变量

进程的并发和进程资源的限制:

ulimit -a

image-20240710174202987

进程的优先级:40级

-20-19

fork创建新进程几乎完全复制父进程的资源,包括但不限于内存、文件描述符、环境变量等。

vfork 完全继承父进程的内存空间,可能会造成内存冲突,因为子进程跟父进程会造成内存共享

进程的并发:

pid_t getpid(void); //如何获取进程的pid
pid_t getppid(void);//如何获取父进程的pid

进程的资源回收

父进程通过fork创建子进程
子进程在内核中也有一个PCB来维护其状态

子进程的时间片耗尽了, 就需要有人回收它的资源
父进程负责回收子进程的资源

如果父进程跟子进程两个进程,

父进程的时间片耗尽,子进程时间片没有耗尽,这时候父进程会被init进程接受,这时候子进程称为“孤儿进程”

子进程时间片耗尽,父进程没有耗尽,但是父进程也没有回收子进程,这时候子进程称为“僵尸进程”

wait(2)//给进程收拾
pid_t wait(int *wstatus); 
WIFEXITED(wstatus) true, 子进程被正常终止 
 		WEXITSTATUS(wstatus) 只有在WIFEXITED 返回真的情况下被使用, 返回子进程退出的状态码
 		WIFSIGNALED(wstatus) true, 子进程是被信号终止 
 		WTERMSIG(wstatus) 返回终止的子进程的信号的编号, 只有在WIFSIGNALED返回真的时候才能被使用	
 	返回值:
 		成功:被终止的子进程的PID
 		错误:-1 errno被设置
waitpid;等待指定的子进程 pid 的状态改变,或者等待满足特定条件的一组子进程。
pid_t waitpid(pid_t pid, int *wstatus, int options); //用于等待子进程状态改变的标准库函数
 	参数:
 	pid:  < -1 等待当前进程组中|pid| 相等的pid的进程的终止
 				-1 等待任意子进程的终止 
 				0  pid==gpid 的子进程的终止
 				> 0 与pid相等的子进程的终止	
 	wstatus:
 	options:
 		 	WNOHANG  子进程被终止,立即返回
 			0:阻塞		
 	返回值:成功 收到了子进程的资源, 立即返回子进程的pid
 					错误 -1
进程关系:
	1. 会话  sid
	每打开一个终端都是创建了一个会话 session
	2. 进程组  gpid
	进程组中第一个进程就是进程组的组长, 同时又是会话组的组长
	3  可以更改进程所在进程组, 但是永远无法脱离会话 用setpgid//用于设置进程组 ID 的系统调用
	int setpgid(pid_t pid, pid_t pgid);
	pid: 要设置进程组 ID 的进程的 PID。如果 pid 等于 0,表示使用调用进程的 PID。
	pgid: 要设置的新进程组 ID。如果 pgid 等于 pid,表示创建一个新的进程组,并将 pid 指		定的进程作为该组的组长

四.更新进程的映像

为了更新进程的映像,采用exec家族函数

execve(2)//更新进程的映像,它替换当前进程的映像为一个新的程序,新程序从其 main 函数开始执行,并且拥有调用 execve 的进程的 PID 和一些其他属性
int execve(const char *pathname,char *const argv[],char *const ebvp[])
参数:pathname:指定要执行二进制的路径
	 argv:传递给新的映像的命令行参数 是一个字符串列表 
				argv[0] 指定了要执行的新的文件名
	 envp: 传递给新的映像的环境变量列表
	 返回值:
			为什么成功不返回
				使用新的映像替换了旧的映像, 旧的映像的代码段 数据段 堆 栈全被覆盖了
			错误 -1 errno被设置
execve 替换当前进程的映像,而不是创建一个新进程。
进程 ID (PID) 保持不变,但是进程的执行内容完全改变。
所有打开的文件描述符、内存段、当前工作目录、根目录、umask 等属性都会被新程序继承。
进程的终止状态和信号处理设置也会被新程序继承

exec 家族的函数
execl
execlp p:路径
execv v:环境变量
execvp

ps -o pid,ppid,pgrp,session,comm

image-20240710213940845

五,守护进程

a.out &  // 加& 将a.out进程放在后台运行 

可以改变进程所在的进程组, 但是无法改变其所在的会话组

setsid (2)

怎默写守护进程流程

1.首先创建子进程,然后让子进程终止pid = fork();
if (pid > 0) {
		exit (0);}
2.使用setsid创建新的会话,让子进程成为会话领导
3.使用 umask(0) 重设文件权限掩码,以确定守护进程创建的文件的权限。
kill -l

image-20240710215153079

一共64个信号 32和33信号不存在 所以一共有62个

可靠信号 又叫实时信号 34~64
不可靠信号 又叫标准信号 1~31

信号就是软中断
中断信号一定由硬件产生!
软中断指的就是软件模拟硬件产生的中断信号

	信号的产生  信号阻塞  信号抵达进程  信号的处理 
	信号的产生到处理之间的状态称为未决状态 pendding  
	未决信号 

信号处理:

​ Ign 忽略信号

signal (3, SIG_IGN);//忽略三号信号

​ Core 接受到信号的进程终止并产生dump文件
​ Stop 接受到信号的进程暂停
​ Cont 接受到信号的进程如果暂停了就继续
​ 大多数信号的默认行为都是终止进程

如何产生信号:

kill 信号编号 pid//1-64个信号量,pid//进程pid
rasie(2);
raise(sig)//信号编号

image-20240710230731374

image-20240710230710523

等待信号

pause  (2)//会挂起调用进程的执行,直到收到一个信号。
sigsuspend (2)//它允许进程在指定的信号集上挂起直到某个信号到达。

改变信号的行为

sigaction(2)//
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum 信号的编号, 也可以是信号的名字
handler 函数指针类型的变量
SIG_DFL SIG_IGN 用户自定义的处理函数

alarm(2)

unsigned int alarm(unsigned int seconds);
		功能:
		产生一个闹钟信号 
		参数:
		seconds, 0, 取消所有的未决闹钟信号 
						 定义的闹钟时间, seconds秒之后发送给进程
		返回值:
				 0 表示没有任何调度的闹钟 所有的闹钟都被执行完毕了
				 闹钟还没有被执行的秒数 

系统在中断时的操作

1.cpu节后中断信号是首先保存当前寄存器的状态

2.保存下一条指令的状态

3.修改模式,从用户模式到中断模式

4.跳转到异常处理函数

5.处理完恢复到异常处理前的状态

6.执行下一条语句

信号的应用

1.漏桶模型

漏桶的速率是恒定的, 不会随着访问量的激增或骤减而变化速率

2.令牌桶模型

令牌三要素

		1. 令牌 token 
		2. 上限 burst
		3. 速率 cps 

名字
handler 函数指针类型的变量
SIG_DFL SIG_IGN 用户自定义的处理函数


alarm(2) 

unsigned int alarm(unsigned int seconds);
功能:
产生一个闹钟信号
参数:
seconds, 0, 取消所有的未决闹钟信号
定义的闹钟时间, seconds秒之后发送给进程
返回值:
0 表示没有任何调度的闹钟 所有的闹钟都被执行完毕了
闹钟还没有被执行的秒数


系统在中断时的操作

1.cpu节后中断信号是首先保存当前寄存器的状态

2.保存下一条指令的状态

3.修改模式,从用户模式到中断模式

4.跳转到异常处理函数

5.处理完恢复到异常处理前的状态

6.执行下一条语句

信号的应用

1.漏桶模型

漏桶的速率是恒定的, 不会随着访问量的激增或骤减而变化速率 

2.令牌桶模型

令牌三要素

	1. 令牌 token 
	2. 上限 burst
	3. 速率 cps 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁生花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值