多线程收尾

目录

  • 其他关于锁的概念
    • 1,单例模式
    • 2,智能指针,STL
    • 3,其他锁
  • 读者写者问题
    • 读者写者的321原则
    • 常用接口
    • 基于读写锁的三种实现方式
  • 自旋锁
    • 自旋锁的接口
    • trylock

其他关于锁的概念

1,单例模式

单例模式。
scott meyer-单例模式和双检查

2,智能指针,STL

智能指针

  • STL中的容器、只能指针都不是线程安全的。

  • 原因是, STL 的设计初衷是将性能挖掘到极致, 而一旦涉及到加锁保证线程安全, 会对性能造成巨大的影响.而且对于不同的容器, 加锁方式的不同, 性能可能也不同(例如hash表的锁表和锁桶).因此 STL 默认不是线程安全. 如果需要在多线程环境下使用, 往往需要调用者自行保证线程安全.

  • 对于 unique_ptr, 由于只是在当前代码块范围内生效, 因此不涉及线程安全问题.对于 shared_ptr, 多个对象需要共用一个引用计数变量, 所以会存在线程安全问题. 但是标准库实现的时候考虑到了这个问题, 基于原子操作(CAS)的方式保证 shared_ptr 能够高效, 原子的操作引用计数.

3,其他锁

  • 悲观锁,在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
  • 乐观锁,:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。

读者写者问题

  • 读写写者问题一般是读者多,写者少的模型。在我们生活中也处处都是这种栗子:
  • 出黑板报,出的人就几个,但是读的人有很多。
  • 基于读者写者地位不同的问题,我们的读写锁也可以实现不同。

读者写者的321原则

  • 读者和读者之间是共享资源的!!因为读者不需要改动数据。
  • 读者和写者之间是互斥。(也可以同步)
  • 写者和写者之间是互斥。(也可以同步)

常用接口

多线程收尾_第1张图片

  • init和destroy函数,传入读写锁,初始化和销毁。

多线程收尾_第2张图片

  • 读者的锁和写者的锁是不同的,所以读者有自己的上锁方式。

多线程收尾_第3张图片

  • 写者的锁。

unlock

  • 它们的解锁都是一样的。

基于读写锁的三种实现方式

  • 1,读者优先。即想尽办法让读者先进行操作。如果临界资源中有读者,就不允许写者进入。如果读者和写者同时竞争锁,那么读者优先。该模式带来的问题就是,写饥饿问题。读者太多,写者等了半天也没有用上临界资源。
  • 2,写者优先,即想尽办法让写者先进行操作。
  • 3,公平使用锁。
  • 我们最常用的还是读者优先。
/********** 这是一段伪代码,用来模拟读者优先的实现 *********/
pthread_rwlock_t reader, writer; //申请两把锁
int reader_nums = 0;  //用来统计读者的个数

/***************** 读者的操作 *****************/
Lock(&reader);
reader_nums++;  //为了保证这一步正确,使用读者锁
if(reader_nums == 1){ //如果有读者,那么就给写者上锁
	Lock(&writer);
}
UnLock(&reader);
//开始读取
Lock(&reader);
reader_nums--;  //保证这一步正确,使用读者锁
if(reader_nums == 0){  //此时没有读者,给写者解锁
	UnLock(&writer);
}
UnLock(&reader);

/*********  写者的操作  **************/
Lock(&writer);
//写入数据
UnLock(&writer);
  • 我们会发现读者锁不是为了防止读者进入,而是为了防止写者进入。你可能会问,那么读者锁有什么用?我直接给写者上锁不就行了?
  • 读者锁是为了保证读者计数器的正确。

自旋锁

  • 有的线程运行世间很短,有的却很长。如果运行时间很长的线程占用了临界资源,那么我们需要让后来的线程挂起。挂起也是需要销毁资源的,把该线程放入等待队列再拿出来。但是,如果该线程运行时间很短,我们直接让后来的线程不断的去申请临界资源,不用去等待了。

多线程收尾_第4张图片

  • 我们锁的实现有可能是在用户态封装的内核态,所以可能造成这样一种情况:内核在自旋申请锁,但是给我们的现象是阻塞。不必惊讶。

自旋锁的接口

多线程收尾_第5张图片

  • 函数名称只需带有spin即可,只展示这一个,不多展示。

trylock

  • 我们正常的申请锁的lock,如果没有申请成功,那么就会阻塞等待。
  • 而trylock是不阻塞等待。你可以设置一个时间(也可以不设置),时间一过,锁如果申请失败,就直接返回。

你可能感兴趣的:(Linux,linux)