最近那个靠谱的小朋友开始看OpenJDK 6的源代码,相比之下真是让我汗颜,我机器里的代码都扔在那儿很久了。
不知道这个小朋友是不是也从main()开始看,还是为了搞明白一些问题而有针对性地去看。反正最近跟我讨论了一些并发、多线程方面的事情,很多概念和算法都是上学时就学了的,但是不出意料我也已经都忘了。于是,呃,现在看来最方便的查资料方式莫过于wikipedia.org了,也不知道会不会出些纰漏,不过英文版比中文版要好很多,内容多,引用和批注看起来也比较充实,暂且相信这么多人的劳动成果吧。摘录一些基本概念:
Critical Section:
临界区。本质上是段代码,其中包含一定需要确保同时只能被一个执行这段代码的线程访问的资源。临界区本身来说并不是实现对资源互斥访问的算法或者机制,一般都需要借用互斥量、信号量之类的结构来确保这种多个线程对这个资源的互斥访问。
Mutex:
mutual exclusion,互斥量,互斥体,互斥锁,whatever,基本带上“互斥”就行,也很常见。最简单的用来确保临街区并发安全的算法或者机制,同时也是用来指代负责在多个线程中协调互斥操作的那个数据结构,我想后面这个用途应该更常见,一般说进入了某个mutex保护的临界区以内为 “持有/获得了某个mutex” 。
Mutex有硬件和软件的实现。硬件实现方面,单处理器机器上一般就是临时禁掉中断和上下文切换,多处理器机上一般用原子的test-and-set操作让几个线程通过一个共享的标志变量做busy-wait,也叫做“自旋锁”(spinlock);软件实现就太多了:Dekker算法,Peterson算法,还有发明Paxos的大神Lamport的面包店算法,以及最近才知道的一个Szymanski算法。这几个算法应该都是lock-free的 (???)。
Semaphore:
信号量有一个初始值用来控制进入临界区的进程/线程数量,从而将并发访问的进程/线程数目控制在初始值限定的数量以下。说到信号量,其实这倒是一个可以从互斥量延展开的概念:互斥量可以看做初始值为1的信号量,而且有些实现里信号量和互斥量的也很类似。信号量有两种操作:P和V,P操作用来将限制并发访问的数值减1,V操作相反。所以一般情况下使用信号量访问共享的资源/数据的时候以P操作开始而以V操作结束,而进行P操作的时候如果信号量的用来控制并发访问的值已经降为0的话,调用P操作的进程/线程就没办法进入临界区而要等待其他进程/线程做完V操作。有的情景中也会把P操作叫做wait,V操作叫做signal。
Monitor:
监视器,对于Java程序员来说这是最熟悉的并发控制单元和概念。简单来说,监视器类似mutex加上wait+signal操作:排他,而且支持不同的线程彼此通过wait和signal操作进行通信。多个线程彼此之间需要协作和某种意义上的通信也算是个可以理解的需求,而无论是获取mutex还是semaphore的P/V操作,都没办法满足多个线程在临界区以内互相协调,所以如果真的遇到了这种需求,只好想方法变通去。监视器正是可以支持多个线程在临界区内进行一些更细粒度的协作——通过wait和signal操作,而且必须保证多个线程在临界区内执行的排他特性。
和信号量的P/V操作——有些时候也会被叫做wait/signal——不同,监视器的wait和signal操作可以让当前线程暂时释放掉已经持有的监视器,当然,因为这个时候当前线程已经进入临界区,所以暂时释放掉监视器以后就不能再继续执行了;然后在其他线程执行同一监视器上的signal方法后,这个暂时释放掉监视器的线程就可以在调用signal的线程离开临界区以后继续从上次调用wait的地方执行。其实对于signal调用后具体应该要决定哪个线程该继续执行也是有两种争论:一是把调用signal的线程挂起,把原来在wait的线程唤起;另一种正相反,调用完signal的线程继续跑,离开临界区之后才轮到原来在wait的线程继续执行。Java应该是后面一种。
基本上应该就这些了吧,没涉及到分布式条件下的互斥和同步。没有太仔细看所以出错了的话还望斧正。
看到Monitor一段,又去翻Hoare的论文,Monitor更确切的含义是Critical Section + wait/signal。
Quoting “暂时释放掉监视器的线程就可以在调用signal的线程离开临界区以后继续从上次调用wait的地方执行”
signaled 线程必须重新获得monitor access,然后退出wait调用,继续执行。
“两种争论”,没看到争论啊, ‘Signal and Wait‘ VS ’Signal and Continue‘。 Java Object.wait() Object.notify(), Object.notifyAll() 是后者。
始终认为通过研究源代码,进行人肉反向工程的方式来获得某个领域的知识是效率低下,不可靠的。
没怎么看明白…
我一直记得是Critical Section自己是什么用都没有的啊,如果monitor光是critical section + wait/signal,那就没了互斥了?critical section随便进么?
那两种争论应该是说调signal了之后是不是调signal的线程挂起,一种是java这种notify/notifyAll立刻返回然后继续执行直到交出monitor,前面调wait才有机会再拿到monitor然后从wait里返回;一种是,我觉着反正挺违反直觉的,继续借用java的API说的话,调notify/notifyAll的交出monitor然后挂起了,前面wait的这个时候有机会拿到monitor从wait返回了。
http://en.wikipedia.org/wiki/Monitor_(synchronization) 里 Blocking condition variables 说的是Hoare style monitor,就是违反(javaer)直觉的那种:With a blocking condition variable, the signaling thread must wait outside the monitor (at least) until the signaled thread relinquishes occupancy of the monitor by either returning or by again waiting on a condition variable.
Nonblocking condition variables说的是Mesa style monitor,才是Java的那种。不过后面又补充说Java其实是Implicit condition variable monitors,这个倒无所谓了,反正java程序员脑袋里肯定也是把当作monitor的对象直接当作condition了,除非用Condition对象。
P.S.,我也不是看JVM源代码看的……我真希望我有时间全看过来……
Hoare也没有给出Monitor的严格定义,只是列举了Monitor应有的特性。
抄Wiki一段,”a critical section is a piece of code that accesses a shared resource (data structure or device) that must not be concurrently accessed by more than one thread of execution”
特别不爱同认真学习的人讨论问题,很快就深入的令人纠结。
你整日晚睡早起,路上飙车,顿顿垃圾快餐,还说没有时间?
-___-# 那有神马好纠结的呢?
老皇历了,现在早/晚睡早起,也没吃啥垃圾快餐啊,啥垃圾不垃圾的,中国专家们骂了人家多少年了,最后还是全民化学家影响下的中餐更NB一些。
6000 doctors prescribing hydroxychloroquine https://hydroxychloroquine.webbfenix.com/
naltrexone 25 mg tablets https://naltrexoneonline.confrancisyalgomas.com/
all natural careprost supplement https://carepro1st.com/