进程打开的文件资源
如何通过代码实现访问fork前打开的文件描述符
//文件描述符
int fd = open();
pid_t n = fork();
if (n == 0)
{
//能不能通过fd访问打开的文件
int num = write (fd, "hello", 5);
if (num == -1)
{
printf("write error");
}
} else
{
sleep(2);//让子进程执行两秒钟
write(fd, "world", 5);
}
close(fd);
用户态到内核态的切换过程
-
内核态拥有我们系统最高访问权限,用户态最低访问权限
-
什么时候需要从用户态切换到内核态?
- 调用系统调用函数
- 触发中断
-
open read write fork 都是系统调用函数
- 系统调用号,每一个系统调用函数都有对应的系统调用号
-
int fd = open()函数的实质;
-
将函数对应的系统调用号保存到eax寄存器中
-
触发0x80中断-》进入到中断处理程序
-
保存程序上下文,为我们将来系统调用函数返回后,恢复现场使用
-
传递系统调用函数的参数
-
真正进入到内核空间,将内核数据段的、局部数据段的存到寄存器上
-
通过sys_open函数返回fd信息
-
-
call[_sys_call_table+eax*4]
//函数调用表 //函数指针数组 _sys_call_table[]= { sys_write; sys_read; ... }
-
返回值通过eax寄存器记录和赋值
孤儿进程
-
父进程结束,子进程未结束,则子进程称之为孤儿进程,但是系统会将所有的孤儿进程托管到系统进程init下,由init统一管理所有的孤儿进程。
int main () { int pif = fork(); assert(-1 != pid); if (pid == 0) { int i = 0; for(;i < 5; i++) { printf("my father is %d\n", getppid()); sleep(1); } } else { ptintf(); } }
僵死进程
-
进程实体结束,被内核释放,但是进程PCB结构依旧保存
-
子进程结束,父进程未结束,并且父进程没有获取子进程退出状态。
int main()
{
pid_t n = fork();
asset(-1 != n);
if (n == 0)
{
printf("i am child, start \n");
sleep(2);
printf("i am child., i will end");
} else {
int pid = wait(NULL);
printf("father pid = %d\n", pid);
pirntf("i am father , stat\n");
sleep(100);
printf("i am father ,i will end");
}
}
-
pid_t wait(int *reval) 获取子进程的退出状态
- 返回值为-1,调用失败
- 返回处理的子进程pid值
- reval:记录子进程退出状态
-
阻塞运行
- 调用函数时,如果条件未发生,则函数不会立即返回,而是等待条件发生
-
非阻塞运行
- 调用函数时,无论条件是否发生,函数都会立即返回
-
调用wait会使父子进程串行运行
- 如何让父子进程并发执行,而且在子进程结束后及时处理僵死进程??
- 父进程不知道子进程什么时候会结束,所以父进程在开始运行时就调用wait等待子进程结束
- 解决方案:父进程在子进程结束后再调用wait,子进程结束之前父进程执行自己的代码
- 父进程如何知道子进程什么时候结束
- 子进程结束时,将这一事件通知给父进程,父进程接受到事件,再去调用wait。
- 父进程如何知道子进程什么时候结束
- 解决方案:父进程在子进程结束后再调用wait,子进程结束之前父进程执行自己的代码
-
信号:信号是操作系统预先定义好的某些事件。信号可以被产生,也可以被接受,产生和接受信号的主体都是进程
- 信号的定义:/usr/include/bits/signum.h
- 信号的定义:/usr/include/bits/signum.h
-
信号的响应方式
-
默认
-
忽略
-
自定义(捕获)
- 如何修改信号的相应方式
typdef void(*sig_Handle)(int *); Sig_Handler signal(int sig_type, Sig_Handle hander); // 信号相应方式(函数地址)
- 子进程结束默认想父进程发送:SINCHLD信号
-