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语言程序并分析其汇编指令执行过程 因 ...
随机推荐
- 【CodeM初赛B轮】A 贪心
[CodeM初赛B轮]A 题目大意:给你一棵树,起初所有点都是白色的,你每次都能选择一个白点i,将这个点i到根路径上的所有到i的距离<k[i]的点都染成黑色(根和i也算,已经被染成黑色的点还是黑 ...
- zoj 3721 Final Exam Arrangement【贪心】
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3721 来源:http://acm.hust.edu.cn/vjudg ...
- Python菜鸟之路:Python基础(二)
一.温故而知新 1. 变量命名方式 旧的方式: username = 'xxxx' password = 'oooo' 新的方式: username, password = 'xxxx', 'oooo ...
- perl智能匹配
1.perl中~~为智能匹配,它能够智能地依据符号两側的操作数来确定操作. 如要推断某个元素是否存在于数组中,不使用智能匹配,程序像这样: my $x=2; my @array=(1,2,3); my ...
- Java内部类(转发:)
内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. 内部类分为: 成员内部类.局部内部类.静态嵌套类.匿名内部类 . 1.成员内部类 成员内部类是最普通的内部类,它的定义为位于另一个类 ...
- IDEA main方法自动补全(转发:http://blog.csdn.net/zjx86320/article/details/52684601)
最近刚从Eclipse转到IDEA,各种学习丫,IDEA里的main方法是不能自动补齐的,肿么办呢? 1.首先,点击File-->Settings-->Editor-->Live T ...
- Oracle数据库体系结构(7) 表空间管理1
表空间是Oracle数据库最大的逻辑存储结构,有一系列段构成.Oracle数据库对象存储结构的管理主要是通过表空间的管理实现的. 1.表空间的分类 表空间根据存储类型不同分为系统表空间和非系统表空间 ...
- python 3 协程函数
python 3 协程函数 1:把函数的执行结果封装好__iter__和__next__,即得到一个迭代器 2:与return功能类似,都可以返回值,但不同的是,return只能返回一次值,而yiel ...
- Android电池驱动【转】
本文转载自:http://blog.sina.com.cn/s/blog_66a6a5ec0100n6ej.html Android的电池的管理分为三个部分:Java部分,JNI部分以及kenel部分 ...
- Nginx/Apache下如何禁止指定目录运行PHP脚本
下面和大家一起分享下如何在Apache和Nginx禁止上传目录里PHP的执行权限. Apache下禁止指定目录运行PHP脚本 在虚拟主机配置文件中增加php_flag engine off指令即可,配 ...