同步优化模式
锁模式
多个应用,如应用A,应用B,共享一个资源,为同步它们对共享资源的访问,锁是最常用的方式,如下:
应用A 应用B
Lock(share) Lock(share)
... ...
UnLock(share) UnLock(share)
通过锁,确保任何时候只有一个应用在访问共享资源;先到先得,后访问的应用必须等待前面的应用操作完成,释放锁之后才能访问。所以,应用A或应用B都有可能因等待锁的释放而延迟。
模拟锁模式
但锁的存在会对性能带来很大的损耗,所以,在对性能要求高的场景,编码中常常需要避免锁的使用。下面的代码完成同样的功能,但没有用到锁。
应用A 应用B
Continue_wait:
If (flagB) wait(); if (flagA) wait();
flagA = 1 flagB = 1
If (flagA){flagB = 0; goto continue_wait;}
... ...
flagA = 0 flagB = 0
无锁模式之一
上述代码用标志替代了锁机制,性能有了一点提高,但无论是应用A,还是应用B,都会“因对方已经占用了资源,自身必须等待(一定时间)”的特征没有改变。
在某些场景下,对涉及共享资源的各方(应用A和应用B)可以区别对待,实际上,在某些包含大数据量的业务中,对涉及共享资源各方的要求是不一样的。比如,大数据量的数据包的接收,解析。一部分应用是可以在来不及处理的情况下丢弃部分数据包的,从统计概率的角度看,这不会影响所承载的业务。
所以,我们可以根据具体的场景做进一步的优化。
应用A 应用B
Try_again:
If (flagB) wait(); if (flagA) break or reurn;
flagA = 1 flagB = 1
If (flagA){flagB = 0; goto try_again;}
... ...
flagA = 0 flagB = 0
这种优化的特点是结合具体业务的实际要求,适当忽略和过滤一部分应用(应用B)对共享资源的访问,以换取整个系统在性能方面的提升。
无锁模式之二
显然,如果根据业务逻辑的设计要求,涉及共享资源访问的各方对共享资源的访问都可以适当的忽略和过滤,那么,前面的模式可以进一步优化为:
应用A 应用B
Try_again:
If (flagB) break or return; if (flagA) break or reurn;
flagA = 1 flagB = 1
If (flagA){flagB = 0; goto try_again;}
... ...
flagA = 0 flagB = 0
上述模型中,应用A或应用B均假定为单一实例,如果存在多个实例,则相应的标志应改为原子操作,以确保标志可以正确赋值。如下:
flagX = 1 改为 atomic_add(flagX)
flagX = 0 改为 atomic_sub(flagX)