并发编程

12.1 基于进程的并发编程

使用fork 每次客户端来请求后,都可以单独开一个子进程对其进行服务(父子进程共享状态信息) 进程的优劣:共享状态信息,但是独享用户地址空间,不用担心覆盖另外一个进程,但也使共享信息状态变得困难(必须显示使用IPC机制)

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

使用select select不会阻塞进程,监听方法执行完毕就完了,但是监听到改动后,会进行阻塞(类似于iOS的通知) 多路复用指的是I/O的读写复用同一个线城 主要是使用select函数来监听描述符状态的变化:例如我们socket添加listen后会返回个描述符,然后描述符的状态是会发生改变的,例如:标准输入,标准输出,标准错误输出,监听到变化后我们做相应的逻辑即可 Node.js nginx 都是基于I/O多路复用的事件驱动的编程方式

12.3 基于线程的并发编程

同一进程内的所有线程共享这个进程虚拟内存地址空间的所有内容,包括它的代码,数据,堆,共享库和打开的文件 但每个线程都有自己的线程上下文,包括:线程ID,栈,栈指针,程序计数器,通用目的寄存器和条件码

主线程和其他线程的区别仅在于它总是进程中第一个运行的线程:一个线程可以杀死它的任何对等线程或者等待它的任意对等线程终止,而且都可以读写相同的共享数据

12.3.5 终止线程

祝线程调用pthread_exit的话,会等待其他对等线程种植,然后再终止主线程和整个进程

12.3.6 分离线程

默认创建的线程都是可结合的线程,可结合的线程能够被其他线程收回和杀死,在被其他线程回收前,它的内存资源是不释放的 一个分离的线程,是不能被其他线程回收和杀死的,但是它的内存资源在它中止是由系统自动释放

12.3.7 初始化线程

pthread_once:允许你初始化与线程例程相关的状态,只有第一次调用才会走回调,之后不做任何事情(我们dispatch_once应该就是调用的这个)

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

线程共享进程的虚拟内存空间,并且不同线程之间不设防,所以可以随意进入某个线程,然后篡改里面的值。这就是线程不好调试,和我们容易出错的一个地方

12.5 用信号量同步线程

共享变量十分方便,但是也引入了同步错误的可能性

为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。

信号量的工作原理: 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的: P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行 V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

信号量除了提供互斥之外,还有一个作用是通过互斥调度堆共享资源的访问

12.7 其他并发问题

  1. 线程安全:主要是指一个函数被多个线程同时调用时,能够确保数据的正确性。不会出现同一时刻对某一变量进行修改这种操作
  2. 可重入性:一个函数被同个线程同时调用时,不会引发任何共享数据
  3. 在线程化的程序中使用已存在的库函数:有些函数本身就是不安全的,这个时候我们要注意,尽量使用线程安全的
  4. 竞争:N个线程都引用了同一个变量,就可能会导致竞争,导致变量的状态不确定
  5. 死锁:一个流永远等待不回发生的事件时就会发生死锁。例如,信号量都是P V的对应起来的,可能某些函数导致多执行了完P后,导致信号量变为0,但是忘记执行V,就会导致其他程序调用该方法的时候一直在等待V,这就是死锁

其他

Web代理是一个在Web服务器和浏览器之间半夜中间角色的程序,浏览器不直接链接服务器获取网页,而是与代理链接,然后代理将请求转发给服务器,服务器向后代理后,代理将相应发给浏览器

并发与并行:并发包括了并行,并发指的是有处理多个任务的能力,不一定时同时。单并行需要同时 线程与进程:进程内部开辟的线程,进程线程间都可以共享数据,但是进程需要用PIC显示共享。线程是并发,进程是并行

资料

  1. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别
  2. linux c学习笔记—-select函数详解

--EOF--

若无特别说明,本站文章均为原创,转载请保留链接,谢谢