APUE读书笔记(18)线程

第十一章 线程

一:主要内容:
  线程可以在单进程环境中执行多个任务,并且一个进程中的所有线程都可以访问该进程的组成部件,比如内存和文件描述符。多线程使得单个资源会被多个用户共享,所以同步机制在多线程中是至关重要的。
二:线程概念
  典型的UNIX进程可以看成只有一个控制线程:一个进程在同一时间只能做一件事情。一个进程对应多个线程有以下好处:
  1.通过对每种事件分配一个单独的处理线程,可以简化处理异步事件的代码。这样就无需考虑单一线程处理多个事件的切换问题。多个线程对应一种事件,每个线程只需要关心自己的那个任务就好了。
  2.多进程下,每个进程不能“简单的”访问到对方的资源,比如内存。但是同一个进程的多个线程却能够很容易的做到。
  3.通过分解问题来提高整个程序的吞吐量。单个线程处理多个问题的时候需要串行化,但是多个线程处理问题可以交叉进行。(仔细想一下,其实并不能提升吞吐量,因为本质上还是串行处理的;但是多线程可以充分利用系统资源,比如系统有十个资源,现在有三个任务,分别需要资源数为:9,8,1,假设这三个任务所需要的时间是不一样的,而且还存在阻塞的时候,比如等待返回结果,那么多线程下完全可以在执行9或者8任务阻塞的时候,来执行1任务)
  4.多线程可以把用户的输入输出的部分与其他部分分开。
三:线程标识
  对应每个进程有一个进程ID做对应,每个线程也有一个线程ID做对应。进程ID在整个系统中都是唯一的,但是线程ID只有在同一个上下文的时候才是唯一的。
  进程ID是一个非负整数,但是线程ID确是一个结构体,所以比较线程ID需要一个函数来进行比较。
在这里插入图片描述
  由于线程ID是一个结构体,所以直接打印线程ID就不可能了,需要借助另一个函数来获取线程ID
在这里插入图片描述
  这样就可以使得每个线程只处理他们对应的那个任务,如下图
在这里插入图片描述
  其中主线程控制任务发给哪个工作线程,工作线程只负责处理对应的作业。
四:线程创建
  新增的线程可以通过函数创建:
在这里插入图片描述
  当线程创建成功的时候,新创建的线程ID会被设置为tidp指向的内存单元,attr参数用于定制各种不同的线程属性。
  新创建的线程会从start_rtn函数的地址开始运行,该函数只有一个参数arg,如果需要执行一个以上的参数,需要把这些参数放入到一个结构体中,然后把结构体的地址作为参数传入。
  线程创建时并不能保证哪个线程会先运行。新创建的线程可以访问进程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的挂起信号集会被清除。
五:线程终止
  如果进程中的任意线程调用了eixt,_exit,Exit;那么整个进程就会终止。单个线程有三种方式可以在不退出进程的方式停止他自己。
  1.线程可以简单的从启动例程返回,返回值是线程的退出码。
  2.线程可以被同一个进程中的其他线程取消。
  3.线程调用pthread_exit
在这里插入图片描述
六:线程同步
  多个控制线程共享相同的内存时,会看到一样的数据,如果多个线程对同一个数据只是读或者每个线程指操作自己的那份数据,都不会存在不一致的问题。但是如果多个线程针对同一个数据又读又写,就会出现问题。读操作是一个时钟周期,写操作是两个时钟周期。为了解决数据不同步的问题,需要使用锁。如果修改操作是原子操作也不会出现问题,
  1.互斥量是一种线程同步的方式,本质上也是一把锁。当多个线程希望对同一个资源进行操作,必须要获得这把锁才行。但是必须要将线程都设计成同一个规则才能保证数据一致,比如如果绝大多数线程都需要先获得锁才能操作,但是有一个线程不需要获得(没有在代码前加上lock操作),那么数据还是不一致的。创建和销毁互斥量:
在这里插入图片描述
  对于锁的操作有以下三种:
在这里插入图片描述
  其中lock和unlock不需要多说,但是trylock是什么?其实trylock是当我们不希望线程阻塞的时候使用的函数。因为正常来说多个线程同时lock的时候,只有抢到锁的线程才能继续执行,如果抢不到,就会进入阻塞状态,知道下一次抢到锁。但是trylock只是尝试加锁,如果抢不到会直接返回EBUSY,不会阻塞。(可能有人会奇怪为什么有trylock,这主要是线程在进行阻塞和活跃切换的时候,需要一些上下文的切换,如果在阻塞不严重的情况下,切换的时间消耗反而更大,所以通过不断地trylock反而可以增加程序执行效率)
  上面执行锁的操作是程序员来控制的,但是如果程序员没有考虑到一些问题,可能会造成死锁的情况。比如某个线程执行加两次锁的操作。
  2.读写锁,读写锁是一种允许更高并发量的锁,读写锁有两种加锁和解锁方式,读加/解锁,写加/解锁。如果锁状态为读加锁,其他的线程也想去读,是可以并发去读的,但是如果为写加锁,那么所有其他线程必须等待本次写操作完成,写解锁之后才能继续执行。读写锁适用的场景为读操作比写操作更多的情况,如果差不多或者写操作更多,适用全局锁会更好。
  3.条件变量,条件变量给多个线程提供了一个会和的场所。条件变量和互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。(具体怎么用没太看明白)
  4.自旋锁,自旋锁也是一种锁,如果不希望线程进入睡眠状态,可以使用自旋锁让线程在等待锁的过程中一直忙等。这可用于加锁的时间极短,并且不希望线程在重新调度花费太多时间的时候适用。
  5.屏障是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所线程都达到某一点,然后从该点继续执行。

发布了51 篇原创文章 · 获赞 7 · 访问量 3693
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览