互斥锁 - 多线程编程那点事 1

Posted 花花酱LeetCode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了互斥锁 - 多线程编程那点事 1相关的知识,希望对你有一定的参考价值。

好久没有码字了,比起录视频码字实在是太幸苦了。。。


最近LeetCode首次增加了多线程编程的题目(1114-1117)。除了算法和数据结构之外,多线程,系统设计是我个人觉得几个非常重要的方向。


不管是刷LeetCode还是日常工作学习,我们编写的程序大部分都是单线程的。随着摩尔定理的逐渐失效,CPU的发展从提高主频转向了多核多线程,学习和掌握多线程编程将毫无疑问会变得越来越重要。


今天我们就一起来聊聊解决多线程问题的一个重要工具Mutex(互斥锁),并用它来解决3道LeetCode的题目。


Mutex是mutual exclusion object的缩写?顾名思义,只有一个人可以通加锁来拥有这个对象。其他人想拥有它?必须等到当前的owner释放锁之后才可以重新获得锁。


Mutex 通常有两个方法:

lock() or aquire()  // 等待直到获取锁

unlock() or release() // 释放锁


今天我们讲两个经典使用场景:

1. 共享资源保护。多个线程,在任意时刻最多只有一个线程可以使用共享资源。


use_private_resource();

m.lock();

use_shared_resource();

m.unlock();

use_private_resource();


在每个需要使用到共享资源的地方 m.lock() 和 m.unlock() 把需要保护的代码包裹(保护)起来,这样就就确保只有一个线程可以使用共享资源。注意不要把可并行执行的部分也保护起来(如下图的a1()/a2()/b1()/b2()),这样虽然没有错,但会降低并行化。


执行的时间轴如上图,print函数由于需要使用共享资源,所以必须顺序执行,其他部分都可以并行执行提高效率。


2. 执行顺序。Thread1执行完foo()后,Thread2才能执行bar()。


要确保执行顺序,在单线程环境下我们只要:


void fun1() { ... foo(); ... }

void fun2() { ... bar(); ... }


fun1();

fun2();


但是在多线程环境下,fun1() 和 fun2() 运行在两个不同的线程上,foo() bar()的执行顺序可以是任意的。要确保bar在foo之后执行,我们定义一个mutex。程序初始化的时候将其锁住。我们在执行bar()函数前需要获取这个锁,由于mutex一开始被锁住了,那么就会等待,bar函数不会被执行。那么来释放这个锁呢?当然是thread1执行完foo()之后释放锁,然后thread2才能获得这个锁,bar()执行。这样就确保了bar()函数一定在foo()函数之后执行。


// Run on an aribitrary thread before starting thread1 and thread2.

void init() { 

  m.lock();  // 初始化对m加锁

}


// Run on thread1

void fun1() { 

  foo(); 

  m.unlock();  // 执行完foo()之后解锁

}


// Run on thread2

void fun2() { 

  m.lock();  // 由于m一开始就锁住了,等fun1解锁

  bar();

  m.unlock(); // optinal 

}


leetcode 1114-1116 三道题目都是这个类型。


互斥锁 - 多线程编程那点事 1

LeetCode 1114, first(), second(), thrid() 需要按顺序执行。定义两个mutex保护second() 和 third() 即可。


LeetCode 1115, foo() bar() 交替执行。定义两个锁,foo() bar() 一人一个。foo解bar的锁,bar解foo的锁。foo需要先执行,所以一开始锁住bar即可。


LeetCode 1116,按顺序打印0102030405... 0一个线程,奇数一个线程,偶数一个线程。需要三个锁,每个线程一个。一开始将奇偶都锁起来,0线程根据下个数的奇偶性释放相对应的锁。奇偶线程打印完之后都释放0的锁。这样就能实现交替打印。


总结一下,在这期节目中我们简单介绍了mutex是什么,以及他的两个经典应用场景,并且用mutex解决3道LeetCode的的题目。在单线程环境下看似平淡无奇的问题在多线程环境下就变得有意思起来,任何东西都是有代价的。


喜欢我们的节目不要忘了关注点赞转发评论。想看视频版的讲解?回复 频道 订阅我的YouTube或者B站就能看到了,每周持续更新中。

以上是关于互斥锁 - 多线程编程那点事 1的主要内容,如果未能解决你的问题,请参考以下文章

分布式锁那点事

多线程编程-- part5.1 互斥锁ReentrantLock

多线程编程之原子锁

多线程编程之自旋锁

多线程编程之自旋锁

多线程编程-- part5.1 互斥锁之公平锁-获取锁