您的位置:首页 > 其它

20145315 《信息安全系统设计基础》第13周学习总结

2016-12-11 19:52 357 查看

20145315 《信息安全系统设计基础》第13周学习总结

课程内容总结

并发:逻辑控制流在时间上是重叠的

基于进程的并发编程

例如:在父进程中接受客户端请求,然后创建新的子进程来为每个客户端服务。

假设我们有两个客户端和一个服务器,服务器正在监听一个监听表述符上的请求。现在假设服务器接受了客户端1的连接请求。

基于进程的并发服务器:

需要包括一个SIGCHID处理程序,来收回将死进程。

父子进程必须关闭它们各个的connfd拷贝。

因套接字的文件表项中的引用计数,直到父子进程的connfd都关闭了,到客户端的连接才会终止。

基于I/O多路复用的并发编程

使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。

select函数处理类型为fd_set的集合,也叫做描述符集合,并在逻辑上描述为一个大小为n的位向量:b_n-1,...b_1,b_0*

描述符:

分配他们

将一个此种类型的变量赋值给另一个变量

用FD_ZERO、FD_SET、FD_CLR和FD_ISSET宏指令来修改和检查它们

基于I/O多路复用的并发事件驱动服务器

比基于进程的设计给了程序员更多的对程序行为的控制。

一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址空间。,使得在流之间共享数据变得容易。

事件驱动设计常常比基于进程的设计要高效得多,因为它们不需要进程上下文切换来调度新进程。

基于线程的并发进程

这是上面两种方法的混合,结合了上面两种方法的特性。

和进程一样,由内核调度,并内核通过一个整数ID来识别线程。

同基于I/O多路复用的流一样,多个线程运行在单一进程的上下文中。因此共享这个进程的虚拟地址空间的整个内容:代码啊,数据,堆,共享库和打开文件。

线程就是运行在进程上下文中的逻辑流。

每个线程都有自己的线程上下文,包括:

一个唯一的整数线程ID



栈指针

程序计数器

通用目的寄存器

条件码

所有运行在一个进程里的线程共享该进程的整个虚拟地址。

主线程:每个进程开始生命周期时都是单一线程,这个线程称为主线程,它是是进程中第一个运行的线程。

对等线程:被主线程创建,后与主线程并发运行。

对等(线程)池:一个线程可以杀死它的任何对等线程,或等待它的任何对等线程终止。每个对等线程都能读写相同的共享数据。

Posix线程:线程代码和本地数据都被封装在一个线程例程中。每个线程都以一个通用指针作为输入,并返回一个通用指针。

创建线程:线程调用pthread_create函数来创建其他线程。

终止线程

顶层的线程返回,隐式终止。

调用pthread_exit函数,显示终止。(会等待所有其他对等线程终止,然后再终止主线程和整个进程,返回thread return)

某个对等线程调用Unix的exit函数,该函数终止进程以及所有与该进程相关的线程。

另一个对等线程以当前线程ID作为参数调用pthread_cancle终止当前进程。

线程调用pthread_join函数等待其他线程终止。这个函数会阻塞,直到线程tid终止,将线程例程返回的(void*)指针赋值为thread_return指向的位置,然后回收已终止线程占用的所有存储器资源.

分离线程:在任何一个时间点上,进程是可结合的或分离的。

初始化进程:调用pthread_once来初始化与线程的相关状态;

多线程程序中的共享变量

根据存储类型被映射到虚拟存储器。

全局变量。函数以外的变量。运行时,虚拟存储器的读/写区域只包含每个全局变量的 一个实例,任何线程可用。

本地自动变量定义在函数内部没有static属性的变量。运行时,每个线程都含有自己的所有本地自动变量实例

本地静态变量。在函数内部,有static。和全局变量一样,虚拟存储器的读/写区域只包含在程序中声明的本地静态变量的一个实例。

共享变量:说一个变量v是共享的,当且仅当它的一个实例被一个以上的线程引用。

进度图

进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线。

将指令执行模型为一种状态到另一种状态的转换。

合法转换:向右或向上。

点(L1,S2)对应线程完成L1,而线程2完成S2状态

信号量:是用信号量解决同步问题,信号量s是具有非负整数值的全局变量,有两种特殊的操作来处理,称为P和V:

P(s):如果s非零,那么P将s减1,并且立即返回。

V(s):V操作将s加1,并重启一个阻塞的线程

使用信号量来实现互斥:将每个共享变量(或者一组相关的共享变量)与一个信号量s(初始为1)联系起来,然后用P(s)和V(s)操作将相应的临界区包围起来。

利用信号量来调度共享资源

生产者-消费者问题:因为插入和取出项目都涉及更新共享变量,所以要保证:对缓冲区的访问是互斥的。

读者-写者问题:修改对象的线程叫做写者;只读对象的线程叫做读者。写者必须拥有对对象的独占访问,而读者可以和无限多个其他读者共享对象。

基于预防线程话的并发服务器

使用线程提高并行性:多核处理可以并行。

其他并发问题

不安全函数类

不保护共享变量的函数

保持跨越多个调用的状态的函数

返回指向静态变量的指针的函数

调用线程不安全函数的函数

可重入函数:被多个线程调用时,不会引用任何共享数据。(是线程安全函数的一个真子集)

显式可重入的:所有函数参数都是传值传递,没有指针,并且所有的数据引用都是本地的自动栈变量,没有引用静态或全剧变量。

隐式可重入的:调用线程小心的传递指向非共享数据的指针。

竞争: 程序员假定线程会按照某种特殊的轨迹穿过执行状态空间,忘了一条准则规定:线程化的程序必须对任何可行的轨迹线都正确工作。

死锁:一组线程被阻塞了,等待一个永远也不会为真的条件。

家庭作业

在这里选择3.67进行分析:

A.

e1.p: 0

e1.x: 4

e2.y: 0

e2.next: 4

B.

总共需要8个字节。

C.

不难知道,赋值前后都应该是整数,

edx就是参数up(一个指针)。

最后结果是用eax - (edx)得到的,说明(edx)是整数,即up->___ 为整数,是e2.y。

再看看之前的eax,eax是由(eax)所得,说明到第3行后,eax是个指针。

它是由(ecx)得到的,说明ecx在第二行也是个指针。

而ecx是通过(up+4)得到的,所以ecx是一个union指针next,即up->e2.next;

到第三行,eax为(ecx),且是一个指针,所以eax在第三行为int* p,即up->e2.next->e1.p。

所以,赋值符号后面的表达式就为 *(up->e2.next->e1.p) - up->e2.y

再看看前面。

最终赋值的地址是 ecx+4,而ecx那时候是一个next指针,而(next+4)必须是一个int,也不难推测它是e1.x。因此前面就为 up->e2.next->e1.x。

结果如下:

void proc(union ele *up)
{
up->e2.next->e1.x = *(up->e2.next->e1.p) - up->e2.y;
}

git截图



学习进度条

代码行数(新增/累积)博客量(新增/累积)学习时间(新增/累积)重要成长
目标5000行30篇400小时
第一周20/2001/220/20
第二周30/2002/418/38
第三周50/2001/422/30
第四周0/2000/00/30
第五周100/2002/225/30
第六周100/2002/225/30
第七周100/2001/225/30
第九周100/2001/225/30
第十周100/2001/225/30
第十一周100/2001/225/30
第十二周100/2001/225/30
第十三周943/2001/225/30

参考资料

《信息安全系统设计基础》教学进程

...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: