操作系统实验一:操作系统初步
操作系统实验一:操作系统初步
李许增 16281042
操作环境:arch Linux
一、(系统调用实验)了解系统调用不同的封装形式。
1、阅读分别运行用API接口函数getpid()直接调用和汇编中断调用两种方式调用Linux操作系统的同一个系统调用getpid的程序(请问getpid的系统调用号是多少?linux系统调用的中断向量号是多少?)。
程序代码1(getpid.c):
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
pid = getpid();
printf("%d\n",pid);
return 0;
}
程序代码2(getpid_break.c):
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
asm volatile(
"mov $0,%%ebx\n\t"
"mov $0x14,%%eax\n\t"
"int $0x80\n\t"
"mov %%eax,%0\n\t"
:"=m" (pid)
);
printf("%d\n",pid);
return 0;
}
程序运行结果:
通过实验程序可知:getpid系统调用号:0x14;Linux系统调用的中断向量号:int 0x80
2、上机完成习题
程序代码1(c语言实现:hello.c):
#include<stdlib.h>
#include<stdio.h>
int main()
{
printf("hello,world!");
return 0;
}
程序代码2(汇编实现:hello.asm):
; hello.asm
section .data ; 数据段声明
msg db "Hello, world!", 0xA ; 要输出的字符串
len equ $ - msg ; 字串长度
section .text ; 代码段声明
global _start ; 指定入口函数
_start: ; 在屏幕上显示一个字符串
mov edx, len ; 参数三:字符串长度
mov ecx, msg ; 参数二:要显示的字符串
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov eax, 4 ; 系统调用号(sys_write)
int 0x80 ; 调用内核功能
; 退出程序
mov ebx, 0 ; 参数一:退出代码
mov eax, 1 ; 系统调用号(sys_exit)
int 0x80 ; 调用内核功能
代码运行结果:
3、阅读pintos操作系统源代码,画出系统调用实现的流程图。
二、(并发实验)根据以下代码完成下面的实验。
程序代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: cpu <string>\n");
exit(1);
}
char *str = argv[1];
while (1)
{
sleep(3);
int j = 100000;
while(j > 0)
{
j--;
}
printf("%s\n", str);
}
return 0;
}
运行结果:
1、 编译运行该程序(cpu.c),观察输出结果,说明程序功能。(编译命令: gcc -o cpu cpu.c –Wall)(执行命令:./cpu)
程序功能:执行命令后提示缺少参数,程序通过C语言”printf”函数实现调用cpu的功能。
2、再次按下面的运行并观察结果:执行命令:./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D &程序cpu运行了几次?他们运行的顺序有何特点和规律?请结合操作系统的特征进行解释。
cpu运行了一次,每次调用输出顺序不变都是A,B,C,D,并且同时输出,证明多个程序运行是在同一时间间隔内,但是他们输出的顺序没有改变cpu在这个时间间隔内运行程序还是有顺序的,这个现象符合并发的概念。Linux为分时操作系统,所以程序执行有时间先后。
三、(内存分配实验)根据以下代码完成实验。
程序代码:
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.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) {
sleep(2);
*p = *p + 1;
printf("(%d) p: %d\n", getpid(), *p); // a4
}
return 0;
}
程序运行结果:
1、阅读并编译运行该程序(mem.c),观察输出结果,说明程序功能。(命令: gcc -o mem mem.c –Wall)
程序观察程序运行时变量被分配的内存地址。
2、再次按下面的命令运行并观察结果。两个分别运行的程序分配的内存地址是否相同?是否共享同一块物理内存区域?为什么?(命令:./mem &; ./mem &)
两次运行程序分配的内存地址不相同(因为变量p分配的地址不同),不共享同一块物理内存区域,两个程序分配的pid不同所以程序不在同一个内存区域上。
3、关闭虚拟内存随机分配程序运行结果
发现两个进程分配内存相同。
四、(共享的问题)根据以下代码完成实验。
程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.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、 阅读并编译运行该程序,观察输出结果,说明程序功能。(编译命令:gcc -o thread thread.c -Wall –pthread)(执行命令1:./thread 1000)
程序可以在执行过程中创建两条线程进行运行,并且调用共享的变量以观察多线程调用的结果。
2、 尝试其他输入参数并执行,并总结执行结果的有何规律?你能尝试解释它吗?(例如执行命令2:./thread 100000)(或者其他参数。)
执行结果程序运行中开了两个线程所以counter的输出应该改为输入数的二倍加入输入为n,则输出应该为2n,带式实际结果出现为部分输出小于2n当然输出结果不可能大于2n。结果出现小于2n的证明多线程调用初夏你了问题,发生了冲突。
3、提示:哪些变量是各个线程共享的,线程并发执行时访问共享变量会不会导致意想不到的问题。
线程共享变量:loops;counter;会导致意想不到的问题,事实证明多线程调用可能存在数据丢失或者数据出错的问题。
github链接: https://github.com/LiXuzeng/2019_OS_LXZ.