能力值:
( LV3,RANK:30 )
2 楼
具体测试用例类似这样:
先申明一个全局变量:
RW_LOCK_TYPE g_RwLock;
需要加读锁时,直接申明一个读锁临时变量:RLock ReadLock(g_RwLock);
在ReadLock这个变量的有效范围内,读锁有效,不需要专门解锁。 需要加写锁时,直接申明一个写锁临时变量:WLock WriteLock(g_RwLock);
在WriteLock这个变量的有效范围内,写锁有效,不需要专门解锁。 支持N次重入,支持占有写锁的线程继续去占有读锁(反过来不允许),写优先。
不支持占有写锁的线程将写锁转换为读锁(目前暂时没这个需要)。
能力值:
( LV2,RANK:10 )
3 楼
有时间看看。
不过我认为这个锁实现的略复杂了,篇幅太长。
能力值:
( LV2,RANK:10 )
4 楼
读写锁,不是简单的互斥加锁。
能力值:
( LV3,RANK:30 )
5 楼
本身就不是简单的互斥加锁。。。所以代码才显得有些复杂。
不然就不会取个“读写锁 ”的名字了
能力值:
( LV2,RANK:10 )
6 楼
我之前做过读写锁,代码不超过200行,所以才说篇幅略长。
能力值:
( LV2,RANK:10 )
7 楼
另,什么场景下会有获取写锁后不释放就再尝试获取读锁的需求?
能力值:
( LV3,RANK:30 )
8 楼
你写了一个函数,里面要获取写锁。
然后你去调用你的同事写的一个函数,这个函数需要保证在读数据时,是没别人写数据的,所以默认加了读锁,且这个函数有两种调用方式:
1、最顶层直接调用,当然没问题。
2、被你加了写锁的那个函数调用。这时如果不支持已经在持有写锁的情况下再次去获取读锁,是要死锁的。难不成这个情况。。。你要求你的同事改函数原型,加个参数告诉内部逻辑是不是要获取读锁?
能力值:
( LV3,RANK:30 )
9 楼
呵呵
你试下那个是不是支持这么多特性就知道究竟需不需要这么长了:
1、只要线程顶层调用的是写锁,后续这个线程里面必须要可以反复多次调用读锁和写锁不死锁
2、写优先
能力值:
( LV2,RANK:10 )
10 楼
嵌套支持先写后读,支持先写后写,支持先读后读,不支持先读后写,也不支持最上层是写里面任意读写
支持写优先和非写优先配置
支持try enter的时候设置超时时间
能力值:
( LV3,RANK:30 )
11 楼
所以嘛,我这个支持了除了你说的支持的外,你不支持的那些情况我这里也有支持,之所以有那些在你口中的“复杂”,也就是因为要支持这些你不支持的,否则这些逻辑很多都不需要。
还有,你的写优先哪里体现出来的
能力值:
( LV3,RANK:25 )
12 楼
TlsAlloc() 只有64个槽
能力值:
( LV3,RANK:30 )
13 楼
那也就是限定了我的测试样例中说的那个全局变量,也就是锁变量,在一个进程范围内最多只可以有32个
这个我想多数时候都够了
而且即使真的出现这个情况,也是有其它方法可以解决的,这个不是什么严重问题
能力值:
( LV2,RANK:10 )
14 楼
你这个支持超时吗
能力值:
( LV3,RANK:30 )
15 楼
超时的逻辑处理起来到不是太复杂
我只要把CRITICAL_SECTION的那几个变量全换成内核事件对象,比如mutex,EVENT等等,就能支持超时处理。你可以看到我那个try函数里是有失败后的处理的,如果换成支持try和超时的内核对象,比如mutex,就很容易做出支持超时的接口了,与try那个区别不大(try那几个接口可以看做是超时为0的支持超时的接口)
不过效率考虑(临界区的效率肯定会比内核对象的效率高很多),加上目前多数时候没这个需求,我不想这么做
能力值:
( LV3,RANK:30 )
16 楼
实际上只要不考虑调用顺序的N种排列组合,读写锁确实几十行一百来行代码能搞定
我最开始的版本没考虑这么复杂的问题,所以就确实只有一百行代码左右
能力值:
( LV4,RANK:50 )
17 楼
这个值得研究一下
能力值:
( LV2,RANK:10 )
18 楼
实现的太复杂了吧。
能力值:
( LV15,RANK:670 )
19 楼
系统不是会扩展的?
找了微软的资料,每个进程最多有 1088 个 tls 槽。
http://msdn.microsoft.com/en-us/library/ms686749.aspx
我试了下 win7 x64 ,控制台空项目,能有 1086 个 tls 槽。
能力值:
(RANK:1130 )
20 楼
1,实现代码太长,隐藏BUG比较多
2,没有timeout的TryxxxLock是没太大意义
3,不能跨平台
4,win7开始,系统有读写锁实现
5,boost库里面也有读写锁
能力值:
( LV2,RANK:10 )
21 楼
The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems. The maximum number of indexes per process is 1,088.
每个进程可以有64个有保证的槽,64个以内可以保证被开辟,64个之外就要看内存使用情况了,但总数绝不会超过1088。原来是这样。
能力值:
( LV3,RANK:30 )
22 楼
第一,代码长短的问题,这个实际上没有个绝对的标准,你说长了就长了吧;关于隐藏bug的,麻烦不吝赐教随便点出几个。
第二,这个之前就说过了,只需要把CRITICAL_SECTION改成支持超时的锁对象,比如event等等,就能有超时机制。
第三,锁机制本身就是与进线程以及操作系统、硬件密切相关的,那些所谓夸平台的锁,无非是写了两份代码,保持了对外接口不变而已。
第四,nt6系统那个锁重入有问题,n久前就试过了
第五,booost那个,不支持锁重入,就是因为这个问题,导致产品出了问题,所以才要自己写。另外有个支持重入的锁,那个没法用在读写锁环境里
能力值:
( LV2,RANK:10 )
23 楼
锁应用timeout是因为线程半路死掉吗
换个互斥体 不过也影响性能
能力值:
( LV3,RANK:30 )
24 楼
与线程半路挂掉没关系,这个与那些带超时机制的普通锁的原因一样,没什么好说的
能力值:
( LV13,RANK:400 )
25 楼
代码不错,但是缺少亮点,锁本来就是一个吃性能的同步工具,楼上有人说复杂也是没错的,个人认为读写锁这种工具在实现其基本功能的前提下,为了保证性能,应该尽量越简洁越好。
一个临界区就够重了,你还用了两个,不要把临界区看得太过高效,对于线程密集型程序来说,临界区的效率随着资源征用的激烈程度而下降,当资源的平均独占时间超过了临界区内的自旋锁的初始值时,临界区的性能就比内核对象还差了,而且会增加功耗。
建议,精简锁的结构,该合并的成员就合并,比如最终合并成一个64位的整数,然后去除临界区,改用整形的原子操作以及CAS模式,这样来降低锁自身的资源占用,提高性能,并且增加可移植性,还有你这个TLS用的也是相当复杂并且不具备移植性,在我看来TLS在这里不如不用。
最后一点,您的代码内存泄露了。
总结,一切把简单问题复杂化,并且最终变得你自己都无法掌控的代码,就是垃圾代码啊,楼主加油,手机打字,不用谢,请叫我红领巾。