2017-2018-1 20179203 《Linux内核原理与分析》第六周作业
攥写人:李鹏举 学号:20179203
( 原创作品转载请注明出处)
( 学习课程:《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 )
一、实验五分析:
1.1 实验要求
1).使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl ,推荐在实验楼Linux虚拟机环境下完成实验。
2).根据本周所学知识分析系统调用的过程,从system_call开始到iret结束之间的整个过程,并画出简要准确的流程图
1.2 实验过程:
1).首先打开Menu文件夹中,修改text.c,并且加入上周的函数getppid():
2).将menu进行编译,make rootfs:
3).检查是否成功的增加了相应的功能:
1.3 实验分析:
通过学习课程我们知道了,linux的系统调用过程:用户程序→C库(即API):INT 0x80 →system_call→系统调用服务例程→内核程序。我们常说的用户API其实就是系统提供的C库。
系统调用是通过软中断指令 INT 0x80 实现的,而这条INT 0x80指令就被封装在C库的函数中。软中断和我们常说的硬中断不同之处在于,软中断是由指令触发的,而不是由硬件外设引起的。INT 0x80 这条指令的执行会让系统跳转到一个预设的内核空间地址,它指向系统调用处理程序,即system_call函数。系统调用处理程序system_call 并不是系统调用服务例程,系统调用服务例程是对一个具体的系统调用的内核实现函数,而系统调用处理程序是在执行系统调用服务例程之前的一个引导过程,是针对INT 0x80这条指令,面向所有的系统调用的。简单来讲,执行任何系统调用,都是先通过调用C库中的函数,这个函数里面就会有软中断 INT 0x80 语句,然后转到执行系统调用处理程序 system_call ,system_call 再根据具体的系统调用号转到执行具体的系统调用服务例程。
而本次实验中我成功的将这个新的函数功能加入了原本的内核菜单中,并且学会了如何清除原来的菜单,下载并更新成为一个新的菜单,可以说学到了Linux内核菜单的修改与覆盖,但是我还是没有实现在自己的虚拟机上实现这些,qemu,git这些指令在虚拟机上都无法使用,导致编译内核这些部分都无法实现,通过今后老师的帮助,希望我的虚拟机可以实现实验楼的全部功能。
最后我做了一个流程图,总结从system_call开始到iret结束的过程:
二、学习总结
本周最重要的知识就是学习了操作系统的资源分配,明白了线程的执行情况,并且通过编程具体的看到了P,V原语的使用。下面就对本周学习到的知识进行小结。
2.1 基础知识
1).万能函数
万能函数主要是利用了void * 可以转变为任何声明类型的原理对函数的类型进行定义,从而声明所要使用的线程函数。例如:void* reader_thread(void * arg)。从这个函数声明中可以看到,函数的类型和变量的类型均使用void * 的手法进行声明,以此使得任意类型的线程都可以用相同的pthread_create线程创建函数创建。
2).临界区与临界资源
首先再次申明一下临界区和临界资源的概念。
临界区:每个进程中访问临界资源的那段代码称为临界区(criticalsection),每次只允许一个进程进入临界区,进入后,不允许其他进程进入。多个进程必须互斥的对它进行访问。
临界资源:各进程采取互斥的方式,实现共享的资源称作临界资源。临界资源是一次仅允许一个进程将使用的共享资源。
通过本次设计的读者写者问题对这一概念做出更加清晰的解释。本次一共分为两个进程读者进程和写者进程,一块内存的共享资源,读者读取其中的信息,写者向其中写入信息。而正在有人写东西的时候肯定不允许有人阅读其中的内容,因为还未写完,读到的内容会出错,因此读者和写者之间对于这块区域的访问应当是互斥的,即有人读时不能写,有人写时不能读,因此两者之间需要一个临界资源。其次当有写者正在进行写的时候其他写者不能同时向其中写入,这样就会覆盖出错,因此写者与写者之间互斥,即任一写者写操作时其他写者等待,因此写者之间同样存在临界资源。
3).P,V原语
PV原语通过操作信号量来处理进程间的同步与互斥的问题。其核心就是一段不可分割不可中断的程序。通过P原语使得临界资源的数量减一,比如读写操作之间互斥,因此有一个临界资源,当读线程进入临界区时,就需要对临界资源进行P操作,这样此时临界资源为0,当写线程到来时再对临界资源进行P操作时发现临界资源已经为0,就无法进入临界区,只有当读线程执行完毕,执行V原语释放临界资源,此时的写线程才能抢到临界资源,进入临界区。
2.2 示例代码分析
#define READER_MAX 3
#define WRITER_MAX 2
int buffer;
首先我定义了读线程和写线程的数量,读线程3个,写线程两个并且我定义了一个读写访问的数据区。
pthread_rwlock_t rw_lock;
这个是至关重要的关于读写者问题的一个定义读写锁,按我自己的理解这个就是C语言库对于读写问题临界资源,以及其中PV原语操作已经定义好的结构体。至于具体的使用下面详细分析。
void* reader_thread(void *arg)
{
static int c = -1;
int i;
while(1) {
c = (c+1) % READER_MAX;//线程号的分配
if(pthread_rwlock_tryrdlock(&rw_lock)) {
printf("读者%u暂时不能读取数据.\n", c);
sleep(2);
} else {
i=c;
printf("读者%u正在读取数据:%d.\n", c,buffer);
sleep(1);
printf("读者%u读取数据完毕.\n", i);
pthread_rwlock_unlock(&rw_lock);
sleep(2);
}
}
}
这是读线程的程序,由buffer的数据区中读出相应的数据,其中需要重点强调的两个语句是pthread_rwlock_tryrdlock(&rw_lock)与 pthread_rwlock_unlock(&rw_lock)。这是读写锁锁定与解锁的操作语句,也就是PV原语。对于读线程的PV原语我认为设计的非常的巧妙,pthread_rwlock_tryrdlock(&rw_lock)这条语句代表着当读线程到来时如果当前没有线程或是读线程占用临界资源则锁定读写锁,而由读线程锁定的读写锁只不允许写线程进入临界区而对读线程不做限制,每个读线程到来时都会对读写锁进行一次锁定。当读取完成后pthread_rwlock_unlock(&rw_lock)解除锁定,只有当所有锁定过的读线程进行了解锁,才会真的解锁读写锁。
void* writer_thread(void *arg)
{
static int p = -1;
int i;
while(1) {
p = (p+1) % WRITER_MAX;
if(pthread_rwlock_trywrlock(&rw_lock)) {
printf("写者%u暂时不能写入数据\n", p);
sleep(2);
}
else {
i=p;
buffer = rand() % 1000;
printf("写者%u正在写入数据:%d.\n", p, buffer);
sleep(2);
printf("写者%u写入数据完毕.\n", i);
pthread_rwlock_unlock(&rw_lock);
sleep(3);
}
}
}
这是写线程的函数,其中pthread_rwlock_trywrlock(&rw_lock)与pthread_rwlock_unlock(&rw_lock)是写线程的PV原语,但是其pthread_rwlock_trywrlock(&rw_lock)P原语与读线程最大的不同是当写线程锁定读写锁后,所有其他读写进程均不能访问临界区,只有当当前的进程完成写操作,进行解锁后才允许其他等待进程访问。
2.3 完整程序代码与运行结果
运行结果:
文字打印的时间还是要长于线程抢占临界资源执行的时间的,所以有些输出的结果显示不能尽如人意。
完整代码:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#define READER_MAX 3
#define WRITER_MAX 2
int buffer;
pthread_rwlock_t rw_lock;
void* reader_thread(void *arg)
{
static int c = -1;
int i;
while(1) {
c = (c+1) % READER_MAX;
if(pthread_rwlock_tryrdlock(&rw_lock)) {
printf("读者%u暂时不能读取数据.\n", c);
sleep(2);
} else {
i=c;
printf("读者%u正在读取数据:%d.\n", c,buffer);
sleep(1);
printf("读者%u读取数据完毕.\n", i);
pthread_rwlock_unlock(&rw_lock);
sleep(2);
}
}
}
void* writer_thread(void *arg)
{
static int p = -1;
int i;
while(1) {
p = (p+1) % WRITER_MAX;
if(pthread_rwlock_trywrlock(&rw_lock)) {
printf("写者%u暂时不能写入数据\n", p);
sleep(2);
}
else {
i=p;
buffer = rand() % 1000;
printf("写者%u正在写入数据:%d.\n", p, buffer);
sleep(2);
printf("写者%u写入数据完毕.\n", i);
pthread_rwlock_unlock(&rw_lock);
sleep(3);
}
}
}
int main(int argc, char* argv[])
{
pthread_t reader, writer;
int i = 0;
pthread_rwlock_init(&rw_lock, NULL);
for(i = 0; i < WRITER_MAX; i++)
pthread_create(&writer, NULL, (void *)writer_thread, NULL);//创建所需数量的线程
for(i = 0; i < READER_MAX; i++)
pthread_create(&reader, NULL, (void *)reader_thread, NULL);
sleep(10);//执行时间为10S
return 0;
}
三、未解决的问题;
通过这次读者写者的问题编写让我了解到了为解决该问题所产生的读写锁,但是与之而来的一个问题就是,真正计算机中可被读写的内存绝不像问题中仅有一块而已,如果写进程来到锁定了读写锁,那么其他读写进程想要访问其他区域也被禁止了吗?肯定是不会的,那么是每一块可被访问的读写区域都有一个相应的读写锁吗?还是说该PV原语还有其他形式的高级应用可以区分线程之间的访问区域,只禁止访问同一区域的线程?真正的编程中又是怎样具体实现的呢?
2017-2018-1 20179203 《Linux内核原理与分析》第六周作业的更多相关文章
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 20169210《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...
- 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业
2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...
- 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...
- 2019-2020-1 20199329《Linux内核原理与分析》第九周作业
<Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...
- 2019-2020-1 20209313《Linux内核原理与分析》第二周作业
2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...
- 2018-2019-1 20189221《Linux内核原理与分析》第一周作业
Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...
- 《Linux内核原理与分析》第一周作业 20189210
实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...
- 2018-2019-1 20189221《Linux内核原理与分析》第二周作业
读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- windows中wamp环境composer使用中openssl问题解决
今天在windows下学习lavaral,使用composer update命令报如下错误: [Composer\Exception\NoSslException] The openssl exten ...
- Lumen开发:phpunit单元测试
先来直接运行,cmd先进入根目录,然后进入tests或是test文件夹 运行命令行:..\vendor\bin\phpunit ExampleTest.php laravel/lumen中集成了PHP ...
- 安装Hadoop 1.1.2 (三 安装配置Hadoop)
1 tar -zxvf hadoop-1.1.2.tar.gz 2 在hadoop/conf目录 (1) 编辑 hadoop-env.sh export JAVA_HOME=/usr/java/jdk ...
- Unity3d 中文菜单
- Dire Wolf(区间DP)
Dire Wolf Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)Total ...
- jedisLock—redis分布式锁实现(转)
一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...
- LeetCode:加一【66】
LeetCode:加一[66] 题目描述 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外 ...
- 【leetcode刷题笔记】Insertion Sort List
Sort a linked list using insertion sort. 题解:实现链表的插入排序. 要注意的地方就是,处理链表插入的时候尽量往当前游标的后面插入,而不要往前面插入,后者非常麻 ...
- nginx日志配置,以及日志轮询
一.为nginx配置错误日志 Nginx错误日志是调试nginx的重要手段,属于核心功能模块的参数(ngx_core_module)该参数名字为err_log,是放在Main区块中全局配置 err_l ...
- java基础部分小项目
贪吃蛇项目 import java.awt.Color; import java.awt.Graphics; import java.awt.Toolkit; import java.awt.even ...