码迷,mamicode.com
首页 > 其他好文 > 详细

第十三周学习报告

时间:2015-12-06 20:42:59      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:

第十二章 并发编程

如果逻辑控制流在时间上重叠,那么它们就是并发的。

使用应用级并发的应用程序称为并发程序,三种基本的构造并发程序的方法:进程、I/O多路复用、线程

12.1基于进程的并发编程

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

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

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

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

12.1.1 基于进程的并发服务器

必须要包括一个SIGCHLD处理程序,来回收僵死子程序的资源

为避免存储器泄露,必须关闭各自的connfd拷贝

直到父子进程的connfd都关闭了,到客户端的的连接才会终止

12.1.2 关于进程的优劣

父子进程间的共享状态信息模型:共享文件表,但是不共享用户地址信息

有独立的地址空间:优点:一个进程不可能不小心覆盖另一个进程的虚拟存储器

缺点:共享状态信息变得困难,必须使用显式的IPC机制;比较慢

?

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

服务器必须响应两个相互独立的I/O事件

  1. 网络客户端发起连接请求
  2. 用户在键盘上键入命令行

基本思路:使用select函数,要求内核挂起进程

Select函数有两个输入:1.读集合的描述符集合 2.基数n

当且仅当一个从该描述符读取一个字节的请求不会阻塞时,描述符k就表示准备好可以读了

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

I/O多路复用可以用做并发事件驱动程序的基础

一个状态机就是一组状态、输入事件和转移

自循环是同一输入和输出状态之间的转移

活动客户端的集合维护在一个pool结构里

在通过调用init_pool初始化池之后,服务器进入一个无限循环

在循环的每次迭代中,服务器调用select函数来检测两种不同类型的输入事件:

  1. 来自一个新客户端的连接请求到达
  2. 一个已存在的客户端的已连接描述符准备好可以读了

Init_pool函数初始化客户端池

Add_client函数添加一个新的客户端到活动客户端池中

Check_clients函数回送来自每个准备好的已连接描述符的一个文本行

  1. I/O多路复用技术的优劣

优点:1.比基于进程的设计给了程序员更多对程序行为的控制

2.每个逻辑流都能访问该进程的全部地址空间

缺点:1.编码复杂 2.不能充分利用多核处理器

?

12.3基于线程的并发编程

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

每个线程都有它自己的线程上下文,包括一个唯一的整数线程ID、栈、栈指针、程序计数器、通用目的寄存器和条件码

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

12.3.1线程执行模型

每个进程开始生命周期时都是单一线程,这个线程称为主线程

在某一时刻,线程创建一个对等线程,从这个时间点开始,两个线程就并发地运行

最后,因为主线程执行一个慢速系统调用,控制就会通过上下文切换传递到对等线程

对等线程执行一段时间,然后控制传递回主线程

12.3.2Posix线程

Posix线程是在C程序中处理线程的一个标准接口

Pthreads运行程序创建、杀死和回收线程,与对等线程安全地共享数据

12.3.3创建线程

Pthread_create函数

创建一个新的线程,并带着一个输入变量arg

在新线程的上下文中运行线程例程f

当其返回时,参数tid包含新创建线程的ID

12.3.4终止线程

方法:1.顶端线程例程返回(隐式)

2.调用pthread_exit函数(显式)

3.某个对等线程调用Unix的exit函数

4.另一个对等线程通过以当前线程ID作为参数调用pthread_cancle函数

12.3.5 回收已终止线程的资源

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

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

12.3.6分离线程

Pthread_detach分离可结合线程tid

线程能够通过以pthread_self()为参数的pthread_detach调用来分离它们

12.3.7 初始化进程

Pthread_once

?

12.4多线程程序中的共享变量

12.4.1 线程存储器模型

一组并发进程运行在一个进程的上下文中

每个线程都有它自己独立的线程上下文

12.4.2 将变量映射到存储器

全局变量是定义在函数之外的变量

本地自动变量就是定义在函数内部但是没有static属性的变量

本地静态变量是定义在函数内部并有static属性的变量

12.4.3 共享变量

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

?

12.5 用信号量同步线程

一般而言,没有办法预测操作系统是否将为线程选择一个正确的顺序,可以借助进度图来阐明

12.5.1 进度图

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

每条轴k对应于进程k的进度

每个点I代表进程已经完成了指令I这一状态

图的原点对应于没有任何线程完成一条指令的初始状态

进度图将指令执行模型化为一种状态到另一种状态的转换

合法的转换是向右或者向上的

操作共享变量cnt内容的指令(L,U,S)构成了一个临界区

两个临界区的交集称为不安全区

绕开不安全区的轨迹线叫做安全轨迹线,反之,叫做不安全轨迹线

?

12.5.2 信号量

信号量s是具有非负整数的全局变量,只能由两种操作处理。

P(s):如果s是非零的,那么P将s减1返回,如果s为零,就挂起

V(s):将s加1,如果有任何线程阻塞在P操作等待s变成非零,那么V操作会重启线程中的一个,然后s减1

?

12.5.3 使用信号量来实现互斥

基本思想:将每个共享变量与一个信号量s联系起来,用P和V操作将临界区包围起来

二元信号量的值总是0或1

以提供互斥为目的的信号量也称为互斥锁

P:加锁 V:解锁

一个被用作一组可用资源的计数器的信号量称为计数信号量

关键思想:创建禁止区

?

12.7 其他并发问题

12.7.1 线程安全

四个线程不安全函数类:

  1. 不保护共享变量的函数
  2. 保存跨越多个调用的状态的函数
  3. 返回指向静态变量的指针的函数
  4. 调用线程不安全函数的函数

12.7.2 可重入性

可重入函数:当它们被多个线程调用时,不会引用任何共享数据

12.7.3 在线程化的程序中使用已存在的库函数

见p693图12-39

除了rand和strtok,所以这些线程不安全函数都是第3类的

12.7.4 竞争

当一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达它的控制流中的x点,就会发生竞争

12.7.5 死锁

信号量引入运行时的错误,叫做死锁

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

互斥锁加锁顺序规则:如果对于程序中每对互斥锁(s,t),给所有的锁分配一个全序,每个线程按照这个顺序来请求锁,并且按照逆序来释放,那么这个程序就是无死锁的。

参考资料:《深入理解计算机系统》

?

?

第十三周学习报告

标签:

原文地址:http://www.cnblogs.com/javablack/p/5024192.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!