教材学习内容总结
网络编程
事务
- 当一个客户端需要服务时,向服务器发送一个请求,发起一个事务。
- 服务器收到请求后,解释它,并以适当的方式操作它的资源。
- 服务器给客户端发送一个相应,并等待下一个请求。
- 客户端收到响应并处理它。
·客户端和服务器都是进程
网络
(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操作将相应的临界区包围起来。
代码托管
https://git.oschina.net/69M/LH20145309_Linux.git