注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mihooke's blog

IT之恋

 
 
 

日志

 
 

《深入理解计算机系统》笔记(八)  

2014-10-01 10:11:45|  分类: 学习录 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


十二、并发编程

1、三种不同的构建并发编程机制:进程、I/O多路复用和线程。

进程是由内核自动调度的,因为它们有各自独立的虚拟地址空间,所以要实现共享数据,必须要有显式的IPCInter-Process Communication进程间通信)机制。事件驱动程序创建它们自己的并发逻辑流,这些逻辑流被模型化为状态机,用I/OO多路复用来显式地调度这些流。因为程序运行在一个单一的进程中,所以流之间共享数据速度很快且很容易。线程是这些方法的综合,同基于进程的流一样,线程也是由内核自动调度的;同I/O多路复用一样,线程也是运行在一个单一进程的上下文中的。

2、基于进程的并发编程,当有多个客户端向服务器发送请求的时候,服务器利用fork生成子进程,让子进程来处理多余的请求。在这个过程中,父、子进程中的已连接描述符connfd)都指向同一个文件表表项,所以父进程关闭它已连接描述符的拷贝是至关重要的。

当父进程派生子进程时,它得到一个已连接描述符的副本,并将相关文件表中的引用计数从1增加到2,当父进程关闭它的描述符副本时,引用计数就从2减到1,内核不会关闭一个文件,直到文件表中它的引用计数减少到0.所以父进程关闭之后,子进程仍然可以和客户端通信。

3、线程:每个进程开始生命周期时都是单一线程,这个线程称为主线程,在某一时刻,线程创建一个对等线程,此后两个线程就并发运行。期间遇到某些情况,主线程切换到对等线程,然后再传递回主线程。

一个线程可以杀死它的任何对等线程。

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

创建线程函数:pthread_create,

#include <pthread.h>

typedef void *(func)(void *)

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

//带着输入变量arg,在新进程的上下文中运行线程例程f,创建新线程的IDtid,参数attr一般是NULL。新线程可以调用pthread_self函数来获得自己的线程ID

终止线程函数:pthread_exit,

void pthread_exit(void *thread_return);

//这个函数会等待所有其他对等线程的终止,然后再终止主线程和整个进程。

回收已终止进程的资源函数:pthread_join,

int pthread_join(pthread_t tid, void **thread_return);

//这个函数会阻塞,直到线程tid终止,将线程例程返回的  (void *)  指针赋值为thread_return指向的位置,再回收资源。

分离线程函数:pthread_detach(pthread_t tid);

线程可分为可结合的和分离的,可结合的能够被其他其他线程回收或杀死,相反,分离的现成不能,它只有在存储器资源终止时由系统释放。现实中,分离的线程用的比较多,可用pthread_detach函数分离可结合线程。

5、初始化线程:

#include <pthread.h>

pthread_once_t  once_control   =  PTHREAD_ONCE_INIT;

int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));

6、多线程中的共享变量

变量根据它们的存储类型被映射到虚拟存储器,全局变量,任何线程都可以引用;本地自动变量,在运行时,每个线程的栈都包含自己的所有本地变量的实例;本地静态变量,虚拟存储器的读/写区域只包含在程序中声明的每个本地静态变量的一个实例。说这个变量是共享的,当且仅当它的一个实例被一个以上的线程引用。

7、信号量同步线程

利用共享变量很方便,但是会造成同步错误,例如,在多个线程对一个全局变量值进行改变的时候,每个并发执行定义了多个线程中的指令的某种全序,这些顺序是不可控制的,有的顺序会产生正确结果,有的不会。可以利用信号量来解决这类问题。

信号量S有两种操作PVP(S),如果S是非0的,PS1,并立即返回;如果S0,那么久挂起这个线程,直到S变为非0,而V操作会重启这个操作,重启之后P操作将S1,并将控制返回给调用者。

V(S)V操作将S1,如果有任何线程阻塞在P操作等待S变成非0,那么V操作会重启这些线程中的一个,然后该线程将S1,完成它的P操作。

V的定义中没有定义等待线程被重启的顺序,唯一的要求是V必须只能重启一个正在等待的线程。

8、信号量函数

#include <semaphore.h>

int sem_init(sem_t *sem, 0, unsigned int value);

int sem_wait(sem_t *s);   //包装为P(sem_t *s),称加锁操作

int sem_post(sem_t *s);   //包装为V(sem_t *s),称解锁操作

信号量可以实现对共享变量的互斥访问,即将每个共享变量以一个信号量S联系起来,然后用PV操作将临界区包围起来。

生产者-消费者问题,是在有限缓冲区中利用PV操作调度;读者-写者问题,是对共享对象的PV操作调度。

并发也带来了竞争和死锁问题。

  评论这张
 
阅读(122)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017