您的位置:首页 > 编程语言

第十二章 并发编程

2015-12-06 00:07 211 查看

第十二章 并发编程

概述:
如果逻辑控制流在时间上重叠,那么他们就是并发的

应用级并发在其他情况下的应用

访问慢速I/O设备

与人交互

通过推迟工作以降低延迟

服务多个网络客户端

在多核机器上进行并发计算

12.1基于进程的并发编程

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


常用函数

fork

exec

waitpid

原理

在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。

12.1.1基于进程的并发服务器

关于服务器需要说明的地方、

要包括一个sigchld处理程序,来回收僵死程序

父子进程必须关闭他们各自的connfd

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

12.1.2关于进程的优劣

1.优点:防止虚拟存储器被错误覆盖

2.缺点:开销高,共享状态信息才需要IPC机制

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

使用I/O多路复用的并发编程的原因

同时响应下面两个请求

网络客户端发起连接请求

用户在键盘上输入命令行

原理

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

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

事件驱动程序:将逻辑流模型化为状态机。

状态机:

状态

输入事件

转移

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

1.优点

相较基于进程的设计,给了程序员更多的对程序程序的控制

运行在单一进程上下文中,所以每个逻辑流都可以访问该进程的全部地址空间,共享数据容易实现

可以使用GDB调试

高效

2.缺点

编码复杂

不能充分利用多核处理器

12.3基于线程的并发编程

是以上两种方法的混合

线程有内核自动调度

多个线程运行在单一进程的上下文中

12.3.2posix线程

void *thread(void *vargp);
int main()
{
pthread_t tid;
Pthread_create(&tid, NULL, thread, NULL);
Pthread_join(tid,NULL);
exit(0);
}

void *thread(void *vargp)
{
printf(“Hello , world\n”);
return NULL;
}

12.3.3创建线程

线程通过调用pthread_create函数来创建其它线程

#include <pthread.h>
typedef void *(func)(void *);

int pthread_create(pthread_t *tid, pthread_attr_t *attr, func *f, void *arg);

12.3.4终止线程

顶层的线程例程返回

调用pthread_exit函数

如果主线程调用,会先等待所有其他对等线程终止,再终止主线程和整个进程,返回值为pthread_return

某个对等线程调用Unix的exit函数,会终止进程与其相关线程

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

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

一个变量是共享的,当且仅当多个线程引用这个变量的某个实例。


12.5用信号量同步线程

第一个 CreateSemaphore

函数功能:创建信号量

函数原型:

HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

LONG lInitialCount,

LONG lMaximumCount,

LPCTSTR lpName

);

函数说明:

第一个参数表示安全控制,一般直接传入NULL。

第二个参数表示初始资源数量。

第三个参数表示最大并发数量。

第四个参数表示信号量的名称,传入NULL表示匿名信号量。

第二个 OpenSemaphore

函数功能:打开信号量

函数原型:

HANDLE OpenSemaphore(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

LPCTSTR lpName

);

函数说明:

第一个参数表示访问权限,对一般传入SEMAPHORE_ALL_ACCESS。详细解释可以查看MSDN文档。

第二个参数表示信号量句柄继承性,一般传入TRUE即可。

第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。

第三个 ReleaseSemaphore

函数功能:递增信号量的当前资源计数

函数原型:

BOOL ReleaseSemaphore(

HANDLE hSemaphore,

LONG lReleaseCount,

LPLONG lpPreviousCount

);

函数说明:

第一个参数是信号量的句柄。

第二个参数表示增加个数,必须大于0且不超过最大资源数量。

第三个参数可以用来传出先前的资源计数,设为NULL表示不需要传出。

由于信号量是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。

12.6使用线程提高并行性

四类线程不安全函数:

不保护共享变量的函数

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

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

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

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


显式可重入:所有函数参数都是传值传递,所有数据引用都是本地自动栈变量


隐式可重入:显式可重入加上一些参数是引用传递(指向非共享数据的指针)


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

线程化的程序必须对任何可行的轨迹线都正确工作

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

死锁不总是可以预测的,而错误常常不可重复。

学习心得

这周的内容和操作系统的内容有相似的地方,都是从分析并发执行的程序的状况。操作系统对于进程的调用,

进程的死锁情况的解决以及更多别的问题讲的更详细。但是本书更注重从代码的角度讲述并发编程的问题,所以通过

学习这门课,使我从不同的角度了解了操作系统。

参考文献:

深入理解计算机系统第十二章

20135202闫佳歆同学的博客

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