进程同步和死锁;事务、悲观锁、乐观锁、表锁、行锁

*)进程并发同步的经典案例,以及产生死锁的情况:

**)生产者消费者

 临界区池子同时只能有一个操作,互斥使用。当一个使用时,另一个需等待。

有一个生产者,一个消费者。生产者能操作的条件:池子只要不满就能生产。消费者能操作的条件:池子只要不空就能消费。

所以,设置互斥信号变量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;

 


 

下面这个过程其实就是“读者和写者”的例子:

MySQL表级锁有两种模式:表共享锁(Table Read Lock)和表独占写锁(Table Write Lock)。
  • 对MyISAM的读操作,不会阻塞其他用户对同一表请求,但会阻塞对同一表的写请求;
  • 对MyISAM的写操作,则会阻塞其他用户对同一表的读和写操作;
  • MyISAM表的读操作和写操作之间,以及写操作之间是串行的。
当一个线程获得对一个表的写锁后,只有持有锁线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。
 
posted @ 2019-04-02 08:26  夏天的尾巴%  阅读(227)  评论(0编辑  收藏  举报