20145219 《信息安全系统设计基础》第13周学习总结
20145219 《信息安全系统设计基础》第13周学习总结
教材学习内容总结
代码运行
-
hello_multi.c
先打印world换行打印hello,间隔1秒再打印相同内容,一共打印5次,最后输出t1,t2 finished
-
hello_multi1.c
-
hello_single.c
打印一个hello,之后每间隔1秒打印一 个hello,共5个;然后打印一个world并换行,之后每间隔1秒打印一个world,共5个
-
incprint.c
在屏幕上换行输出count=1,2,3,4,5,间隔1秒
-
twordcount1.c
统计两个file的words数
-
twordcount2.c
引入pthread_mutex_t,统计两个file的words数
-
twordcount3.c
先统计两个file各自的words数,再统计两个file的总words数
-
twordcount4.c
先输出两个file各自的信息和words数,再统计两个file的总words数
-
condvar.c
消费者等待生产者产出产品后才打印,否则消费者阻塞等待生产者生产。
-
count.c
创建两个线程共享同一变量,都实现加一操作
-
countwithmutex.c
引入互斥锁(Mutex)解决访问冲突的问题
-
cp_t.c
将源文件复制到目的文件,并在其中创建num个线程
运行:./cp_t [源文件名] [目的文件名] [创建线程数]
-
createthread.c
打印进程和线程ID
-
semphore.c
信号量,打印product和consume
-
share.c
获得线程的终止状态
-
threadexit.c
输出3个线程的状态
第十一章 网络编程
-
客户端-服务器编程模型
1、组成
- 一个服务器进程 -> 管理某种资源 -> 通过操作这种资源来为它的客户端提供某种服务
- 一个或多个客户端进程
客户端和服务器都是进程
2、基本操作:事务
-
网络
1、对主机而言:网络是一种I/O设备
通过DMA(直接存储器存取方式)传送:从网络上接收到的数据从适配器经过I/O和存储器总线拷贝到存储器
2、物理上:网络是一个按照地理远近组成的层次系统
最底层是LAN(局域网),最流行的是以太网
3、协议
互联网重要特性:由采用不同技术,互不兼容的局域网和广域网组成,并能使其相互通信。其中不同网络相互通信的解决办法是一层运行在每台主机和路由器上的协议软件,消除不同网络的差异。
协议提供的两种基本能力
- 命名机制:唯一的标示一台主机
- 传送机制:定义一种把数据位捆扎成不连续的片的同一方式
4、全球IP因特网
TCP/IP协议族
混合使用套接字接口函数和UnixI/O函数进行通信
世界范围的主机集合特性:
- 主机集合被映射为一组32位的IP地址
- 这组IP地址被映射为一组称为因特网域名的标识符
- 因特网主机上的进程能够通过连接和任何其他主机上的进程
5、检索并打印一个DNS主机条目
-
套接字
-
Web服务器
1、HTTP (Hypertext Transfer Protocol,超文本传输协议)
Web 客户端和服务器之间交互时用的一个基于文本的应用级协议。
HTTP 是一个简单的协议。
一个 Web 客户端(即浏览器) 打开一个到服务器的因特网连接,并且请求某些内容。服务器响应所请求的内容,然后关闭连接。浏览器读取这些内容,并把它显示在屏幕上。
2、内容
Web内容可以用一种叫做 HTML(Hypertext Markup Language,超文本标记语言)的语言来编写。一个 HTML 程序(页)包含指令(标记),它们告诉浏览器如何显示这页中的各种文本和图形对象。
第十二章 并发编程
-
概述
1、并发:逻辑控制流在时间上重叠。
2、并发程序:使用应用级并发的应用程序。
3、三种基本的构造并发程序的方法:
- 进程,用内核来调用和维护,有独立的虚拟地址空间,显式的进程间通信机制。
- I/O多路复用,应用程序在一个进程的上下文中显式的调度控制流。逻辑流被模型化为状态机。
- 线程,运行在一个单一进程上下文中的逻辑流。由内核进行调度,共享同一个虚拟地址空间。
-
基于进程的并发编程
1、构造并发程序最简单的方法就是用进程。
一个构造并发服务器的自然方法就是,在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。
2、基于进程的并发服务器
通常服务器会运行很长的时间,所以我们必须要包括一个 SIGCHLD 处理程序,来回收僵死 (zombie) 子进程的资源。当 SIGCHLD 处理程序执行时, SIGCHLD 信号是阻塞的,而 Unix 信号是不排队的。
父子进程必须关闭它们各自的 connfd 拷贝。父进程必须关闭它的已连接描述符,以避免存储器泄漏。直到父子进程的 connfd 都关闭了,到客户端的连接才会终止。
3、进程的优劣
父、子进程间共享状态信息,进程有一个非常清晰的模型:共享文件表,但是不共享用户地址空间。
进程有独立的地址空间既是优点也是缺点:
- 优点:一个进程不可能不小心覆盖另一个进程的虚拟存储器,这就消除了许多令人迷惑的错误。
- 缺点:独立的地址空间使得进程共享状态信息变得更加困难。为了共享信息,它们必须使用显式的IPC(进程间通信)机制。基于进程的设计的另一个缺点是,它们往往比较慢,因为进程控制和 IPC 的开销很高。
-
基于 I/O 多路复用的并发编程
1、I/O 多路复用(I/O multiplexing) 技术:基本的思路就是使用 select 函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。
2、基于 I/O 多路复用的并发事件驱动服务器
I/O 多路复用可以用做并发事件驱动 (event-driven) 程序的基础,流是因为某种事件而前进的。
将逻辑流模型化为状态机:一个状态机 (state machine) 就是一组状态 (state)、输入事件(input event) 和转移(transition),其中转移就是将状态和输入事件映射到状态。每个转移都将一个(输入状态,输入事件)对映射到一个输出状态。自循环(self-loop) 是同一输入和输出状态之间的转移。节 点表示状态,有向弧表示转移,而弧上的标号表示输入事件。一个状态机从某种初始状态开始执行。每个输入事件都会引发一个从当前状态到下一状态的转移。
服务器使用I/O多路复用,借助 select 函数检测输入事件的发生。服务器调用 select 函数来 检测两种不同类型的输人事件:
- 来自一个新客户端的连接请求到达
- 一个己存在的客户端的己连接描述符准备好可以读了。
3、I/O 多路复用技术的优劣
优点:
- 它比基于进程的设计给了程序员更多的对程序行为的控制。
- 一个基于 I/O 多路复用的事件驱动服务器是运行在单一进程上下文中的,因 此每个逻辑流都能访问该进程的全部地址空间。
缺点:编码复杂。
-
基于线程的并发编程
1、线程(thread) :运行在进程上下文中的逻辑流。
2、每个线程都有它自己的线程上下文 (thread context),包括一个唯一的整数线程 (Thread ID, TID)、栈、栈指针、程序计数器、通用目的寄存器和条件码。
3、所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间。
4、基于线程的逻辑流结合了基于进程和基于 I/O 多路复用的流的特性。线程由内核自动调度,并且内核通过一个整数 ID 来识别线程。
5、线程执行模型
主线程:每个进程开始生命周期时都是单一线程
对等线程:某一时刻,主线程创建的对等线程
6、Posix 线程
Posix 线程 (Pthreads) 是在 C 程序中处理线程的一个标准接口。定义了大约 60 个函数,允许程序创建、杀死和回收线程,与对等线程安全地共享数据,还可以通知对等线程系统状态的变化。
线程的代码和本地数据被封装在一个线程例程(thread routine) 中。
7、创建线程
pthread_create 函数创建一个新的线程,并带着一个输入变量arg,在新线程的上下文中运行线程例程f。用attr参数来改变新创建线程的默认属性。 返回时,参数 tid包含新创建线程的ID。新线程可以通过调用 pthreadself 函数来获得它自己的线程 ID。
8、终止线程
- 当顶层的线程例程返回时,线程会隐式地终止。
- 通过调用 pthreadexit 函数,线程会显式地终止。如果主线程调用 pthreadexit , 它会等待所有其他对等线程终止,然后再终止主线程和整个进程,返回值为 thread_return。
9、回收已终止线程的资源
线程通过调用 pthread_join 函数等待其他线程终止。pthread _join函数会阻塞,直到线程tid终止,回收已终止线程占用的所有存储器资源。pthread _join函数只能等待一个指定的线程终止。
10、分离线程
在任何一个时间点上,线程是可结合的 (joinable) 或者是分离的 (detached)。
一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是没有被释放的。
一个分离的线程是不能被其他线程回收或杀死的。它的存储器资源在它终止时由系统自动释放。
默认情况下,线程被创建成可结合的,为了避免存储器漏洞,每个可集合的线程都应该要么被其他进程显式的回收,要么通过调用pthread _detach函数被分离。
11、初始化线程
pthread_once 函数允许你初始化与线程例程相关的状态。
12、一个基于线程的并发服务器
调用 pthread_ create 时,如何将已连接描述符传递给对等线程。最明显的方法就是传递一个指向这个描述符的指针。 对等线程间接引用这个指针,并将它赋值给一个局部变量。
-
多线程程序中的共享变量
1、线程存储器模型
一个变量是共享的,当且仅当多个线程引用这个变量的某个实例。
2、将变量映射到存储器
全局变量:虚拟存储器的读/写区域只会包含每个全局变量的一个实例。
本地自动变量:定义在函数内部但没有static属性的变量。
本地静态变量:定义在函数内部并有static属性的变量。
3、共享变量
变量是共享的<=>它的一个实例被一个以上的线程引用
-
用信号量同步线程
1、进度图
进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线,原点对应于没有任何线程完成一条指令的初始状态。
转换规则:
合法的转换是向右或者向上,即某一个线程中的一条指令完成 两条指令不能在同一时刻完成,即不允许出现对角线 程序不能反向运行,即不能出现向下或向左
线程循环代码的分解:
H:在循环头部的指令块 L:加载共享变量cnt到线程i中寄存器%eax的指令 U:更新(增加)%eax的指令 S:将%eax的更新值存回到共享变量cnt的指令 T:循环尾部的指令块
临界区:对于线程i,操作共享变量cnt内容的指令L,U,S构成了一个关于共享变量cnt的临界区。
2、信号量
信号量定义:
type semaphore=record count: integer; queue: list of process end; var s:semaphore;
使用信号量来实现互斥基本思想:将每个共享变量(或者一组相关的共享变量)与一个信号量s(初始为1)联系起来,然后用P和V操作将相应的临界区包围起来。
读者—写者问题:
(1)读者优先,要求不让读者等待,除非已经把使用对象的权限赋予了一个写者。 (2)写者优先,要求一旦一个写者准备好可以写,它就会尽可能地完成它的写操作。 (3)饥饿就是一个线程无限期地阻塞,无法进展。
-
使用线程提高并行性
写顺序程序只有一条逻辑流,写并发程序有多条并发流,并行程序的集合是并发程序集合的真子集。
-
其他并发问题
1、线程安全
一个线程是安全的,当且仅当被多个并发线程反复的调用时,它会一直产生正确的结果。
2、可重入性
显式可重入的:所有函数参数都是传值传递,没有指针,并且所有的数据引用都是本地的自动栈变量,没有引用静态或全剧变量。
隐式可重入的:调用线程小心的传递指向非共享数据的指针。
3、在线程化的程序中使用已存在的库函数
线程不安全函数的可重入版本,名字以_r为后缀结尾。
4、竞争
发生的原因:一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达它的控制流中的x点。也就是说,程序员假定线程会按照某种特殊的轨迹穿过执行状态空间,忘了一条准则规定:线程化的程序必须对任何可行的轨迹线都正确工作。
消除方法:动态的为每个整数ID分配一个独立的块,并且传递给线程例程一个指向这个块的指针
5、死锁
一组线程被阻塞了,等待一个永远也不会为真的条件。死锁是不可预测的。
本周代码托管截图
- 代码托管连接
- 第1~4周项目分文件夹时弄乱了已删除,从第五周开始存在新项目里。
- PS:git上学期用还好好的,这学期就总是会出问题,果然当初新建项目时很重要,新建的项目格式有问题之后调整就很费劲,总是会莫名其妙(其实是对git命令的含义不了解)的传不上去,或者全部覆盖(碰见问题按照百度解决时跟自己预期的结果不同)……还好我的代码一直留着,覆盖也只是重新传一次相同的,就是上传时间会改……
本周代码行数统计截图
其他(感悟、思考等,可选)
本周学习的主要内容是多线程,首先学习了课本上的第十二章,书面上了解并发的相关知识——进程、线程、I/O多路复用……使我对于并发是怎么进行的有了一个大概的理解,能够理解这种并发进行的思想。然后,结合老师上传的代码,我又掌握了对于多线程的程序的编译运行的方法。在代码理解的方面我还存在一些欠缺,这周末并没有完全理解透彻,将会在之后补上来。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第零周 | 0/0 | 1/1 | 15/15 | 安装虚拟机 |
第一周 | 0/0 | 1/2 | 25/40 | 学习Linux命令 |
第二周 | 62/62 | 1/3 | 25/65 | 学习C编程 |
第三周 | 176/238 | 1/4 | 20/85 | 学习数的表示和计算 |
第五周 | 57/295 | 1/5 | 20/105 | 学习汇编语言,了解逆向思想 |
第六周 | 150/445 | 1/6 | 25/130 | 学习Y86处理器和HCL硬件描述语言 |
第七周 | 115/560 | 1/7 | 20/150 | 学习存储器相关知识 |
第八周 | 0/560 | 2/9 | 30/180 | 期中总结 |
第九周 | 186/746 | 2/11 | 20/200 | Unix I/O及相关函数 |
第十周 | 423/1169 | 2/13 | 23/223 | man、grep、cp、echostate、fileinfo、filesize、ls、setecho、spwd、testioctl、who代码的理解与调试 |
第十一周 | 1034/2203 | 2/15 | 31/254 | 学习异常控制流,并理解、运行老师给的代码 |
第十二周 | 29/2232 | 2/17 | 23/277 | 复习前三周内容,继续理解、运行代码,学习signal相关视频 |
第十三周 | 821/3053 | 1/18 | 19/296 | 网络编程、并发、进程、多线程 |