16281003杜璨-第一次实验报告

第一次实验报告

一、(系统调⽤用实验)了了解系统调⽤用不不同的封装形式。

要求:

1、参考下列列⽹网址中的程序。阅读分别运⾏行行⽤用API接⼝口函数getpid()直接调⽤用和汇编中断调⽤用两种⽅方 式调⽤用Linux操作系统的同⼀一个系统调⽤用getpid的程序(请问getpid的系统调⽤用号是多少?linux系统调⽤用的 中断向量量号是多少?)。

2、上机完成习题1.13。

3、阅读pintos操作系统源代码,画出系统调⽤用实现的流 程图。

1.程序一运行结果:
在这里插入图片描述

程序二运行结果:
在这里插入图片描述
getpid系统调用号:39
linux系统调用的中断向量号80

2.c语言代码:

#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
printf(%d\n”,pid)
}

运行代码
在这里插入图片描述
汇编代码:

.section .data
message:
    .ascii "hello world!\n"
    length = . - message
    .section .text
    .global _start      
_start:
    movq $1, %rax     
    movq $1, %rdi      
    lea message(%rip), %rsi 
    movq $length, %rdx
    syscall
    movq $60, %rax    
    xor %rdi, %rdi     
    syscall

运行.s文件
在这里插入图片描述

3.流程图
在这里插入图片描述

二、(并发实验)根据以下代码完成下面的实验。

要求:1.编译运行该程序(cpu.c),观察输出结果,说明程序功能。 (编译命令: gcc -o cpu cpu.c –Wall)(执行命令:./cpu)

2、再次按下面的运行并观察结果:执行命令:./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D &程序cpu运行了几次?他们运行的顺序有何特点和规律?请结合操作系统的特征进行解释。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include "common.h"

int
main(int argc, char *argv[])
{
 if (argc != 2) {
 fprintf(stderr, "usage: cpu <string>\n");
 exit(1);
 }
 char *str = argv[1];
 while (1) {
 spin(1);
 printf("%s\n", str); 
 }
 return 0;

1.运行程序结果
在这里插入图片描述

该程序实现的是,调Spin()一个反复检查时间并一旦运行一秒钟就返回的函数Spin()。 然后,它打印出用户在命令行上输入的字符串,并一直重复。如果输入的参数不为两个,便输出usage: cpu 。

2.按下面的运行执行命令:./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D
运行结果:
在这里插入图片描述

我认为cpu一共运行了四次,这个程序反反复复检查时间,直到一秒钟过去。 第二次过去后,代码会用户传入的输入字符串,然后继续。 程序会永远运行。虽然看起来cpu进行了多次的运行,但是操作系统在硬件的帮助下实现了虚拟化cpu,所以系统看起来具有大量虚拟CPU。把单个CPU转换为看起来无限数量的CPU,从而让许多程序看起来一次运行。

三、(内存分配实验)根据以下代码完成实验。

要求:

1.阅读并编译运行该程序(mem.c),观察输出结果,说明程序功能。(命令: gcc -o mem mem.c –Wall)

2、再次按下面的命令运行并观察结果。两个分别运行的程序分配的内存地址是否相同?是否共享同一块物理内存区域?为什么?命令:./mem &; ./mem & 进程码 指针

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"

int main(int argc, char *argv[])
 {
 int *p = malloc(sizeof(int)); // a1
 assert(p != NULL);
 printf("(%d) address pointed to by p: %p\n",
 getpid(), p); // a2
 *p = 0; // a3
 while (1) {
 Spin(1);
 *p = *p + 1;
 printf("(%d) p: %d\n", getpid(), *p); // a4
 }
 return 0;

1.运行程序截图
在这里插入图片描述
分析运行结果:
程序的功能为:首先,分配一些内存。 然后,它印出内存地址,然后将数字0放入新分配的内存的第一个位置。 最后循环:延迟一秒并递增存储在p中保存的地址的值。 对于每个print语句,它还会打印出正在运行的程序的进程标识符(PID)。 该PID在每个运行过程中都是唯一的。
新分配的内存位于地址0x1628010。 程序运行时,会慢慢更新值并打印出结果。

2.运行结果截图
在这里插入图片描述

第一个运行的程序分配到的内存地址为0x417010,第二个运行的程序分配到的内存地址为0x1981010
正在运行的程序都有自己的私有内存,而不是与其他正在运行的程序共享相同的物理内存。因为操作系统虚拟化了内存。 每个进程访问自己的私有虚拟地址空间,操作系统以某种方式映射到机器的物理内存。 一个正在运行的程序中的内存引用不会影响其他进程的地址空间;而对于运行程序而言,它拥有所有的物理内存。 然而,现实是物理内存是由操作系统管理的共享资源。

四、(共享的问题)根据以下代码完成实验。

要求:

1.阅读并编译运行该程序,观察输出结果,说明程序功能。(编译命令:gcc -o thread thread.c -Wall –pthread)(执行命令1:./thread 1000)

2.尝试其他输入参数并执行,并总结执行结果的有何规律?你能尝试解释它吗?(例如执行命令2:./thread 100000)(或者其他参数。)

3.提示:哪些变量是各个线程共享的,线程并发执行时访问共享变量会不会导致意想不到的问题。

#include <stdio.h>
#include <stdlib.h>
#include "common.h"

 volatile int counter = 0;
 int loops;

 void *worker(void *arg) {
 int i;
 for (i = 0; i < loops; i++) {
 counter++;
 }
return NULL;
 }

 int
 main(int argc, char *argv[])
 {
 if (argc != 2) {
 fprintf(stderr, "usage: threads <value>\n");
 exit(1);
 }
 loops = atoi(argv[1]);
 pthread_t p1, p2;
 printf("Initial value : %d\n", counter);

 Pthread_create(&p1, NULL, worker, NULL);
 Pthread_create(&p2, NULL, worker, NULL);
 Pthread_join(p1, NULL);
 Pthread_join(p2, NULL);
 printf("Final value : %d\n", counter);
 return 0;

1.运行结果截图
在这里插入图片描述
主程序使用Pthread .create()创建两个线程。每个线程开始在一个名为worker()的例程中运行,是循环递增一个统计循环次数的计数器。循环的值确定两个工作程序中的每一个将在循环中递增共享计数器的次数。两个线程完成时,计数器的最终值为2000,因为每个线程将计数器递增1000次。 实际上,当循环的输入值设置为N时,程序的最终输出应该为2N

2.我发现如果增大输入值,结果并不会如我所愿,输出2N,会得到错误的数值,而且每次输出都会不同。因为上面程序,共享计数器递增,一共拥有三个指令:用于递增,用于把计数器中的值加载到寄存器中,把它储存回内存,这三个指令不是一次全部执行完,所以这个是并发中存在的问题。

GitHub链接:https://github.com/mitsdisy/OS

猜你喜欢

转载自blog.csdn.net/qq_42474446/article/details/88619434