2017-2018-1 20155217 《信息安全系统设计基础》第八周学习总结
2017-11-11 20:00
555 查看
2017-2018-1 20155217 《信息安全系统设计基础》第八周学习总结
第八周课下作业2(课上没完成的必做)
- 把课上练习3的daytime服务器分别用多进程和多线程实现成并发服务器并测试 - 提交博客链接
因为之前在实验楼里做的实践,没有办法从外网上找相关运行代码,所以没有完成。课下重新安装了虚拟机,本次课下作业便是在虚拟机里完成的。
多线程
echoserveri.c :echoclient.c:
参考在Ubuntu下使用 csapp.h 和 csapp.c,学习、修改并学会使用csapp.h 和 csapp.c
代码运行截图:
多进程
echoserverp.c:#include "csapp.h" void echo(int connfd) { size_t n; char buf[MAXLINE]; rio_t rio; Rio_readinitb(&rio, connfd); while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { printf("server received %d bytes\n", n); Rio_writen(connfd, buf, n); } } void sigchld_handler(int sig) { while (waitpid(-1, 0, WNOHANG) > 0) ; return; } int main(int argc, char **argv) { int listenfd, connfd, port, clientlen=sizeof(struct sockaddr_in); struct sockaddr_in clientaddr; if (argc != 2) { fprintf(stderr, "usage: %s <port>\n", argv[0]); exit(0); } port = atoi(argv[1]); Signal(SIGCHLD, sigchld_handler); listenfd = Open_listenfd(port); while (1) { connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen); if (Fork() == 0) { Close(listenfd); echo(connfd); Close(connfd); exit(0); } Close(connfd); /* Parent closes connected socket (important!) */ } }
代码运行截图:
教材学习内容总结
第十二章 并发编程
并发:逻辑控制流在时间上重叠并发程序:使用应用级并发的应用程序称为并发程序
三种基本的构造并发程序的方法:
(1)进程,用内核来调用和维护,有独立的虚拟地址空间,显式的进程间通信机制。 (2)I/O多路复用,应用程序在一个进程的上下文中显式的调度控制流。逻辑流被模型化为状态机。 (3)线程,运行在一个单一进程上下文中的逻辑流。由内核进行调度,共享同一个虚拟地址空间。
12.1 基于进程的并发编程
构造并发服务器的自然方法就是,在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。因为父子进程中的已连接描述符都指向同一个文件表表项,所以父进程关闭它的已连接描述符的拷贝是至关重要的,而且由此引起的存储器泄露将最终消耗尽可用的存储器,使系统崩溃。
12.1.1 基于进程的并发服务器
(1)需要一个SIGCHLD处理程序,来回收僵死子进程的资源。 (2)父子进程必须关闭各自的connfd拷贝。对父进程尤为重要,以避免存储器泄露。 (3)套接字的文件表表项中的引用计数,直到父子进程的connfd都关闭了,到客户端的连接才会终止。
12.2 基于I/O多路复用的并发编程
echo服务器必须响应两个相互独立的I/O时间:(1)网络客户端发起连接请求 (2)用户在键盘上键入命令行。
I/O多路复用技术的基本思路:使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。
将描述符集合看成是n位位向量:b(n-1),……b1,b0
每个位bk对应于描述符k,当期仅当bk=1,描述符k才表明是描述符集合的一个元素。可以做以下三件事:
(1)分配它们; (2)将一个此种类型的变量赋值给另一个变量; (3)用FDZERO、FDSET、FDCLR和FDISSET宏指令来修改和检查它们。
12.2.2 I/O多路复用技术的优势
事件驱动器的设计优点:
(1)比基于进程的设计给了程序员更多的对程序行为的控制 (2)运行在单一进程上下文中,因此,每个逻辑流都能访问该进程的全部地址空间,使得流之间共享数据变得很容易。 (3)不需要进程上下文切换来调度新的流。
缺点:
(1)编码复杂 (2)不能充分利用多核处理器
12.3 基于线程的并发编程
线程:运行子啊进程上下文中的逻辑流。线程有自己的线程上下文,包括一个唯一的整数线程ID、栈、栈指针、程序计数器、通用目的寄存器和条件码。所有运行在一个进程里的线程共享该进程的整个虚拟地址空间。
12.3.1 线程执行模型
线程与进程的不同:
(1)线程的上下文切换要比进程的上下文切换快得多; (2)和一个进程相关的线程组成一个对等池,独立于其他线程创建的线程。 (3)主线程和其他线程的区别仅在于它总是进程中第一个运行的线程。
对等池的影响
(1)一个线程可以杀死它的任何对等线程; (2)等待它的任意对等线程终止; (3)每个对等线程都能读写相同的共享资源。
12.3.4 终止线程
终止方式:
(1)当顶层的线程例程返回时,线程会隐式的终止; (2)通过调用pthread _exit函数,线程会显示地终止。如果主线程调用pthread _exit,它会等待所有其他对等线程终止,然后再终止主线程和整个进程。
12.3.6 分离线程
在任何一个时间点上,线程是可结合的或者是分离的。一个可结合的线程能够被其他线程收回其资源和杀死;一个可分离的线程是不能被其他线程回收或杀死的。它的存储器资源在它终止时有系统自动释放。
默认情况下,线程被创建成可结合的,为了避免存储器漏洞,每个可集合的线程都应该要么被其他进程显式的回收,要么通过调用pthread _detach函数被分离。
12.4 多线程程序中的变量共享
12.4.2 将变量映射到存储器全局变量:虚拟存储器的读/写区域只会包含每个全局变量的一个实例。
本地自动变量:定义在函数内部但没有static属性的变量。
本地静态变量:定义在函数内部并有static属性的变量。
12.5 用信号量同步线程
线程i的循环代码分解为五部分:Hi:在循环头部的指令块 Li:加载共享变量cnt到寄存器%eax的指令,%eax表示线程i中的寄存器%eax的值 Ui:更新(增加)%eax的指令 Si:将%eaxi的更新值存回到共享变量cnt的指令 Ti:循环尾部的指令块。
12.5.3 使用信号量来实现互斥
二元信号量:将每个共享变量与一个信号量s联系起来,然后用P(S)和V(s)操作将这种临界区包围起来,这种方式来保护共享变量的信号量。
互斥锁:以提供互斥为目的的二元信号量
加锁:一个互斥锁上执行P操作称为对互斥锁加锁,执行V操作称为对互斥锁解锁。对一个互斥锁加了锁但还没有解锁的线程称为占用了这个互斥锁。
计数信号量:一个呗用作一组可用资源的计数器的信号量
12.5.4 利用信号量来调度共享资源
读者—写者问题:
(1)读者优先,要求不让读者等待,除非已经把使用对象的权限赋予了一个写者。 (2)写者优先,要求一旦一个写者准备好可以写,它就会尽可能地完成它的写操作。 (3)饥饿就是一个线程无限期地阻塞,无法进展。
12.7 其他并发问题
线程安全:当且仅当被多个并发线程反复地调用时,它会一直产生正确的结果。线程不安全:如果一个函数不是线程安全的,就是线程不安全的。
线程不安全的类:
(1)不保护共享变量的函数 (2)保持跨越多个调用的状态的函数。 (3)返回指向静态变量的指针的函数。解决办法:重写函数和加锁拷贝。 (4)调用线程不安全函数的函数。
12.7.2 可重入性
可重入函数:当它们被多个线程调用时,不会引用任何共享数据。可重入函数是线程安全函数的一个真子集 。
关键思想是我们用一个调用者传递进来的指针取代了静态的next变量。
显式可重入:没有指针,没有引用静态或全局变量
隐式可重入:允许它们传递指针
可重入性即使调用者也是被调用者的属性,并不只是被调用者单独的属性。
教材学习中的问题和解决过程
问题1:怎样会造成死锁状态?问题1解决方案:程序员使用P和V操作不当,以至于两个信号量的禁止区域重叠。且死锁状态是不可预测的。
问题2:线程对等池的影响是什么?
问题2解决方案:(1)一个线程可以杀死它的任何对等线程;(2)等待它的任意对等线程终止;(3)每个对等线程都能读写相同的共享资源。
代码调试中的问题和解决过程
问题1:condvar解决方案:由于调用了pthread,gcc编译的时候要加上-lpthread选项。在pthread库中通过条件变量来阻塞等待一个条件,或者唤醒等待这个条件的线程。
代码托管
结对及互评
点评模板:
博客中值得学习的或问题:xxx
xxx
...
代码中值得学习的或问题:
xxx
xxx
...
其他
本周结对学习情况
- [20155236](http://www.cnblogs.com/fcgfcgfcg/) - 结对照片 - 结对学习内容 12.4.1 线程存储器模型 1、每个线程和其他线程一起共享进程上下文的剩余部分。包括整个用户虚拟地址空间,是由只读文本、读/写数据、堆以及所有的共享库代码和数据区域组成的。线程也共享同样的打开文件的集合。 2、任何线程都可以访问共享虚拟存储器的任意位置。寄存器是从不共享的,而虚拟存储器总是共享的。 12.4.2 将变量映射到存储器 1、全局变量:虚拟存储器的读/写区域只会包含每个全局变量的一个实例。 2、本地自动变量:定义在函数内部但没有static属性的变量。 3、本地静态变量:定义在函数内部并有static属性的变量。 12.4.3 共享变量 变量v是共享的,当且仅当它的一个实例被一个以上的线程引用。
其他(感悟、思考等,可选)
第十二章的很多内容是和前面联系在一起,现在看来可以理解的知识,如果是在刚开学的时候去读,就未必理解得了,也从一个角度说明慢慢积累的重要性,也可以说“厚积薄发”吧。学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 |
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
参考:软件工程软件的估计为什么这么难,软件工程 估计方法
计划学习时间:XX小时
实际学习时间:XX小时
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)
参考资料
《深入理解计算机系统V3》学习指导...
相关文章推荐
- 2017-2018-1 20155333 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155211 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155210 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155317《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 学号20155209 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155227 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155232 《信息安全系统设计基础》第八周学习总结以及课下补做
- 2017-2018-1 20155312 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155217 《信息安全系统设计基础》第十四周学习总结
- 2017-2018-1 20155216 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155217 《信息安全系统设计基础》第一周学习总结
- 2017-2018-20155336 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155301 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155217 《信息安全系统设计基础》第七周学习总结
- 2017-2018-1 20155203 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155308 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155217 《信息安全系统设计基础》第十三周学习总结
- # 2017-2018-1 20155224 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155233 《信息安全系统设计基础》第八周学习总结
- 2017-2018-1 20155217 《信息安全系统设计基础》第十一周学习总结