*)进程并发同步的经典案例,以及产生死锁的情况:
**)生产者消费者
临界区池子同时只能有一个操作,互斥使用。当一个使用时,另一个需等待。
有一个生产者,一个消费者。生产者能操作的条件:池子只要不满就能生产。消费者能操作的条件:池子只要不空就能消费。
所以,设置①互斥信号变量mutex,wait(mutex);设置②池子数量变量m,判断是=n还是=0。
生产者操作时判断:if(m<n),wait(mutex),满足时即可操作;消费者操作时判断:if(m>0),wait(mutex),满足时即可操作;
死锁情况:上面的2个条件判断,当把mutex判断放到前面时,会造成死锁。比如:池子中数量=0时,消费者先wait(mutex),拿到了使用权,然后wait(m>0)。此时生产者因为等不到mutex,所以一直在等待。消费者也一直在等待m>0,陷入死锁。
**)哲学家进餐
一张圆桌上,坐5个哲学家,每个哲学家面前有一个盘子,每个哲学家的左手边有一根筷子,右手边有一根筷子。也就是说,这张桌子上,5个人、5个盘子、5根筷子。只有当一个哲学家同时拿起左右2根筷子时才能吃饭。
死锁情况:当5个哲学家都拿起左/右边的筷子时,5个哲学家都在等待右/左边的筷子,陷入一直等待的死锁。
打破死锁的解决办法:只有判断当左右2根筷子都可用时,哲学家才能做拿起筷子这个动作。
**)读者和写者
有一个写者,多个读者,一个操作区。写者和读者不能同时操作,多个读者可以同时操作。
变量:记录正在操作的读者的个数readCount。当readCount=0时,写者才能操作。
这个例子就是实际数据库锁的常见例子,比如:行锁、表锁。
*)什么是死锁
一组进程中,每一个进程都在等待资源,但某个进程等待的资源都被这一组的其他进程占用了,造成了无限等待,进程无法进行下去,就是死锁。
**)死锁的条件
有一个临界区(允许被多个进程使用的资源,但同时只能有一个进程使用,当一个进程在使用时,其他进程必须等待)
死锁必备的4个必要条件:1.互斥。对临界区资源排他性使用。2.请求和保持。一个进程在等待临界资源时,对自己已经拿到的资源保持不放。3.不剥夺。临界资源只能等待这个进程释放,其他进程不能剥夺。4.环路等待。多个进程等待的资源形成了一个闭环,他们互相等待对方。
解决死锁的途径,就是打破这4个条件中的某一个或者某几个。比如打破第2个,进程请求资源一段时间之后,如果还没得到,就释放自己已经有的资源。这样就打破了死锁的僵局了。
悲观锁乐观锁和事务的隔离级别: http://www.cnblogs.com/otomedaybreak/archive/2012/01/27/2330008.html (很好的文章)
表锁、行锁:参考文档:https://www.cnblogs.com/chenqionghe/p/4845693.html
- 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
表锁:给正在操作的表加锁,使用方法:
1 LOCK tables orders read local,order_detail read local; 2 SELECT SUM(total) FROM orders; 3 SELECT SUM(subtotal) FROM order_detail; 4 Unlock tables;
下面这个过程其实就是“读者和写者”的例子:
- 对MyISAM的读操作,不会阻塞其他用户对同一表请求,但会阻塞对同一表的写请求;
- 对MyISAM的写操作,则会阻塞其他用户对同一表的读和写操作;
- MyISAM表的读操作和写操作之间,以及写操作之间是串行的。