20145228 《信息安全系统设计基础》第十三周学习总结 (2)

教材学习内容总结

网络编程

事务

  • 当一个客户端需要服务时,向服务器发送一个请求,发起一个事务。
  • 服务器收到请求后,解释它,并以适当的方式操作它的资源。
  • 服务器给客户端发送一个相应,并等待下一个请求。
  • 客户端收到响应并处理它。

·客户端和服务器都是进程

网络

(1)对主机而言:网络是一种I/O设备

从网络上接收到的数据从适配器经过I/O和存储器总线拷贝到存储器,典型地是通过DMA(直接存储器存取方式)传送。

(2)物理上:网络是一个按照地理远近组成的层次系统

最底层:LAN(局域网),最流行的是以太网。

并发编程

•并发:出现在计算机系统的许多不同层面上。

现代操作系统提供了三种基本的构造并发程序的方法:

•进程。每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程 有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信(IPC)机制。

•I/O 多路复用。在这种形式的并发编程中,应用程序在一个进程的上下文中显式地调度它们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态。因为程序是一个单独的进程,所以所有的流都共享同一个地址空间。

•线程。线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度。是其他两种方式的混合体,像进程流一样由内核进行调度,而像I/O 多路复用流一样共享同一个虚拟地址空间。

基于进程的并发编程

•构造并发程序最简单的方法就是用进程。

一个构造并发服务器的自然方法就是,在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。

·第一步:服务器接受客户端的连接请求

·第二步:服务器派生一个子进程为这个客户端服务

·第三步:服务器接受另一个连接请求

·第四步:服务器派生另一个子进程为新的客户端服务

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

服务器使用I/O多路复用,借助 select 函数检测输入事件的发生。

服务器调用 select 函数来 检测两种不同类型的输人事件:

  1. 来自一个新客户端的连接请求到达

  2. 一个己存在的客户 端的己连接描述符准备好可以读了。

优点:

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

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

缺点:编码复杂

基于线程的并发编程

基于线程的逻辑流结合了基于进程和基于 I/O 多路复用的流的特性。同进程一样,线程由内核自动调度,并且内核通过一个整数 ID 来识别线程。同基于 I/O 多路复用的流一样,多个线程 运行在单一进程的上下文中,因此共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件。

·线程的上下文切换要比进程的上下文切换快得多。

·不是按照严格的父子层次来组织的。

·和一个进程相关的线程组成一个对等(线程)池 (pool),独立于其他线程创建的线程。

·主线程和其他线程的区别仅在于它总是进程中第一个运行的线程。

·对等 (线程)池概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止。

·每个对等线程都能读写相同的共享数据。

(1)Posix线程

Posix 线程是在C程序中处理线程的一个标准接口。Pthreads定义了大约60个函数,允许程序创建、杀死和回收线程,与对等线程安全地共享数据,还可以通知对等线程系统状态的变化。

(2)创建线程

pthread_create 函数创建一个新的线程,并带着一个输入变量arg,在新线程的上下文中运行线程例程f。能用attr参数来改变新创建线程的默认属性。

当 pthreadcreate 返回时,参数 tid包含新创建线程的ID。新线程可以通过调用 pthreadself 函数来获得它自己的线程 ID.

(3)终止线程

当顶层的线程例程返回时,线程会隐式地终止。 通过调用 pthreadexit 函数,线程会显式地终止。如果主线程调用 pthreadexit , 它会等待所有其他对等线程终止,然后再终止主线程和整个进程,返回值为 thread_return。

(4)回收已终止线程的资源

线程通过调用 pthread_join 函数等待其他线程终止。

•pthreadjoin 函数会阻塞,直到线程 tid 终止,将线程例程返回的 (void*) 指针赋值为 threadreturn 指向的位置,然后回收己终止线程占用的所有存储器资源。

•pthread join 函数只能等待一个指定的线程终止。

(5)分离线程

默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程都应该要么被其他线程显式地收回,要么通过调用 pthread_detach 函数被分离。

•pthreaddetach 函数分离可结合线程 tid. 线程能够通过以 pthreadself()为参数的 pthread_detach 调用来分离它们自己。

(6)初始化线程

pthread_once 函数允许你初始化与线程例程相关的状态。

共享变量

变量是共享的<=>当且仅当它的一个实例被一个以上的线程引用

进度图

进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线,原点对应于没有任何线程完成一条指令的初始状态。

当n=2时,状态比较简单,是比较熟悉的二维坐标图,横纵坐标各代表一个线程,而转换被表示为有向边

转换规则:

  • 合法的转换是向右或者向上,即某一个线程中的一条指令完成
  • 两条指令不能在同一时刻完成,即不允许出现对角线
  • 程序不能反向运行,即不能出现向下或向左

而一个程序的执行历史被模型化为状态空间中的一条轨迹线。

•线程循环代码的分解:

H:在循环头部的指令块 L:加载共享变量cnt到线程i中寄存器%eax的指令。 U:更新(增加)%eax的指令 S:将%eax的更新值存回到共享变量cnt的指令 T:循环尾部的指令块

•临界区:对于线程i,操作共享变量cnt内容的指令L,U,S构成了一个关于共享变量cnt的临界区。

•不安全区:两个临界区的交集形成的状态

•安全轨迹线:绕开不安全区的轨迹线

信号量

信号量实现互斥的基本原理

•两个或多个进程通过传递信号进行合作,可以迫使进程在某个位置暂时停止执行(阻塞等待),直到它收到一个可以“向前推进”的信号(被唤醒);

•将实现信号灯作用的变量称为信号量,常定义为记录型变量s,其一个域为整型,另一个域为队列,其元素为等待该信号量的阻塞进程(FIFO)。

•使用信号量来实现互斥基本思想

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

部分代码截图

基于进程的并发echo服务器

代码托管

代码托管地址

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 4000行 30篇 350小时
第一周 0/ 0 2/2 20/30
第二周 100/100 1/3 20/50
第三周 300/400 1/4 20/70
第四周 0/400 0/4 0/70
第五周 300/700 2/6 20/90
第六周 100/800 2/8 20/110
第七周 100/900 2/10 20/130
第八周 0/900 3/13 20/150
第九周 200/1100 3/16 20/170
第十周 300/1400 3/19 25/195
第十一周 500/1900 3/22 25/230
第十二周 0/1900 3/25 10/240
第十三周 500/2400 2/27 25/265

参考资料

posted @ 2016-12-11 15:09  20145228江苒  阅读(209)  评论(1编辑  收藏  举报