OSTEP Chapter 6 回顾
这里回顾第6章,本章介绍了机制:受限直接执行。
书籍介绍:
学习资料:
- https://pages.cs.wisc.edu/~remzi/OSTEP/
- https://github.com/remzi-arpacidusseau/ostep-translations/tree/master/chinese
- https://github.com/joshuap233/Operating-Systems-Three-Easy-Pieces-NOTES
参考资料:
- https://www.cnblogs.com/bwbfight/p/11181631.html
- https://blog.csdn.net/u014530704/article/details/73848573
- https://www.cnblogs.com/kunhu/p/3608109.html
- https://blog.csdn.net/qq_42914528/article/details/82023408
参考资料:
- https://github.com/joshuap233/Operating-Systems-Three-Easy-Pieces-NOTES/blob/main/06.%E7%AC%AC%E5%85%AD%E7%AB%A0-%E6%9C%BA%E5%88%B6:%E5%8F%97%E9%99%90%E5%88%B6%E7%9B%B4%E6%8E%A5%E6%89%A7%E8%A1%8C/code/test-content-switch.c
- https://blog.csdn.net/Z_Stand/article/details/107883684
- https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html
- https://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
- https://blog.csdn.net/xyjsshijia/article/details/86572807
- https://blog.csdn.net/wennuanddianbo/article/details/79304869
- https://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html
第6 章 机制:受限直接执行
内容回顾
关键概念
- 时分共享(time sharing):运行一个进程一段时间,然后运行另一个进程,如此轮换。
- 挑战:
- 性能
- 控制权
- 挑战:
- 受限制的操作
- 用户模式和内核模式
- 如果用户程序需要执行系统调用,那么会通过陷阱(trap)指令跳入内核,并将特权级别提升到内核模式;完成系统调用,操作系统调用一个特殊的从陷阱返回(return-from-trap)指令返回到发起发起调用的用户程序,同时将特权级别降低到用户模式
- 陷阱表(trap table)告诉硬件在发生某些异常事件时要运行哪些代码
- 在进程之间切换
- 协作方式:等待系统调用
- 非协作方式:操作系统进行控制
- 利用时钟中断。产生中断时,当前正在运行的进程停止,操作系统中预先配置的中断处理程序(interrupt handler)会运行。此时,操作系统重新获得CPU 的控制权,因此可以做它想做的事:停止当前进程,并启动另一个进程。
- 保存和恢复上下文
- 切换进程的操作称为上下文切换(context swtich)
- 操作系统为当前正在执行的进程保存一些寄存器的值,为即将执行的进程恢复一些寄存器的值,这样从陷阱返回时不会回到之前运行的进行。
- 切换进程的操作称为上下文切换(context swtich)
作业(测量)
1
系统调用时间测量,反复调用read 0字节:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
int N = 10000;
int main() {
struct timeval start;
struct timeval end;
double t = 0;
char buf[1024];
gettimeofday(&start, NULL);
for (int i = 0; i < N; i++) {
read(STDIN_FILENO, buf, 0);
}
gettimeofday(&end, NULL);
t = end.tv_sec * 1000000.0 + end.tv_usec - start.tv_sec * 1000000.0 - start.tv_usec;
printf("系统调用执行时间为:%f微秒\n", t / N);
return 0;
}
运行:
╰─○ make sys_call && ./sys_call
make: 'sys_call' is up to date.
系统调用执行时间为:0.626900微秒
下上文切换时间测量:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/time.h>
// 需要添加
#define __USE_GNU
#include <sched.h>
#include <pthread.h>
int N = 10000; //00000;
int main() {
// I/O
int fd1[2];
int fd2[2];
// 保存结果
int fd[0];
// CPU核的mask
cpu_set_t mask;
CPU_ZERO(&mask);
// 设置第一个CPU
CPU_SET(0, &mask);
// 保证子进程先运行
const struct sched_param param = {sched_get_priority_min(SCHED_FIFO)};
// 时间
struct timeval start;
struct timeval end;
// 管道1
int r1 = pipe(fd1);
if (r1 < 0) {
printf("pipe failed\n");
exit(1);
}
// 管道2
int r2 = pipe(fd2);
if (r2 < 0) {
printf("pipe failed\n");
exit(1);
}
// 保存结果
int r = pipe(fd);
if (r < 0) {
printf("pipe failed\n");
exit(1);
}
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
// 保证子进程先运行, 需要sudo
if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) == -1) {
printf("set scheduler failed!\n");
exit(1);
}
// 设置CPU
if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &mask) == -1) {
printf("Set child process affinity failed!\n");
exit(1);
}
// 关闭读端
close(fd[0]);
// 得到起始时间
gettimeofday(&start, NULL);
for (int i = 0; i < N; i++) {
// 子进程向pipe1写入
write(fd1[1], "a", 1);
// 子进程从pipe2读取
read(fd2[0], NULL, 0);
}
// 传递给父进程
write(fd[1], &start, sizeof(start));
// 关闭写端
close(fd[1]);
} else {
// 父进程
// 设置CPU
if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &mask) == -1) {
printf("Set parent process affinity failed!\n");
exit(1);
}
// 关闭写端
close(fd[1]);
for (int i = 0; i < N; i++) {
// 父进程向pipe2写入
write(fd2[1], "a", 1);
// 父进程从pipe1读取
read(fd1[0], NULL, 0);
}
gettimeofday(&end, NULL);
// 获得子进程中的时间
read(fd[0], &start, sizeof(start));
double t = end.tv_sec * 1000000.0 + end.tv_usec - start.tv_sec * 1000000.0 - start.tv_usec;
printf("上下文切换执行时间为:%f微秒\n", t / N);
// 关闭读端
close(fd[0]);
}
return 0;
}
运行:
╰─○ make cont_switch && sudo ./cont_switch
make: 'cont_switch' is up to date.
上下文切换执行时间为:2.055700微秒
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere