map值为指针时多线程该怎么保护指针?

C++语言 码拜 10年前 (2015-05-11) 1285次浏览 0个评论

我现在在模仿写一个数据库缓存的功能,

有一个单例类管理着 map<int, *p> 变量

提供接口访问和修改,我在写入的时候上锁,读的时候没有。

因为会有删除的情况,所以现在情况是这样的:

线程A读的时候获取了map的一份拷贝,对pA进行操作。

正常情况下, 
if (pA)

   pA->DoSth();
}

是没问题的。

但如果这个时候有线程B,获取了map的引用,然后把pA删除掉了。

回到线程A的情况,线程A在if(pA)的时候,p所指向的对象还没有被删除,所以进入了if里面,但是切换到了线程B,线程B把p指向的对象删除掉了。这个时候回到线程,pA->DoSth();就会出错

请问一下大家是怎么处理这种情况的?

我设计的时候,其实一个map就对应数据库的一张表,int是表记录的主键,有多少条记录就有多少个*p;

之所以这样设计,是因为不同的表创建一个类,他们都继承同一个类,这样存的时候无论什么表的类,都能直接存到map里面,用的时候在强转回表的类就行了。

这种情况应该怎么避免pA->DoSth()出错呢?对map读上锁感觉太耗性能了

20分
读写锁
你测试过读写锁是性能瓶颈?还是臆想的?
20分
读写的并发程度很高吗
40分
        在保证正确性的前提下再考虑性能,你光顾着性能的话,那写的时候也可以不用加锁啦
        读的时候不加锁,对于线程A来说是不负责任的,因为你没法控制系统的线程调度,除非此时线程B也是执行的读操作,那么你也许会想:可不可以对B的操作进行判断,如果是读操作A就不加锁,否则就加锁,哈哈,关键是A根本就不知道B会干什么,所以A要自保,所以读的时候也加上锁!
        至于性能,你可以从别的方面下手,比如优化整体的流程,架构。
引用 1 楼 yangyunzhao 的回复:

读写锁
你测试过读写锁是性能瓶颈?还是臆想的?

引用 2 楼 fly_dragon_fly 的回复:

读写的并发程度很高吗

还没测试过,主要是数据会频繁操作,所以才把数据库的内容读到内存里面操作。

我读没上锁,因为网上搜了一些资料好像都说读的时候不上锁,写的时候才上锁。

因为我读的时候是获取map的一份拷贝,然后在操作的 =- =

引用 3 楼 youjun610789338 的回复:

        在保证正确性的前提下再考虑性能,你光顾着性能的话,那写的时候也可以不用加锁啦
        读的时候不加锁,对于线程A来说是不负责任的,因为你没法控制系统的线程调度,除非此时线程B也是执行的读操作,那么你也许会想:可不可以对B的操作进行判断,如果是读操作A就不加锁,否则就加锁,哈哈,关键是A根本就不知道B会干什么,所以A要自保,所以读的时候也加上锁!
        至于性能,你可以从别的方面下手,比如优化整体的流程,架构。

如果要上读写锁,是为每一个类都加吗?因为是这样的,map<int, *p> 有a1、a2、a3、a4等等,然后a1里面可能存了1000条记录。如果我读或者写a1里面的第一条数据时上锁,另外线程读写第1000条记录,却因为只给a1上锁而等待第一条处理完。总觉得有点浪费。。

还是我想太多有强迫症 = =···

引用 1 楼 yangyunzhao 的回复:

读写锁
你测试过读写锁是性能瓶颈?还是臆想的?

引用 2 楼 fly_dragon_fly 的回复:

读写的并发程度很高吗

引用 3 楼 youjun610789338 的回复:

        在保证正确性的前提下再考虑性能,你光顾着性能的话,那写的时候也可以不用加锁啦
        读的时候不加锁,对于线程A来说是不负责任的,因为你没法控制系统的线程调度,除非此时线程B也是执行的读操作,那么你也许会想:可不可以对B的操作进行判断,如果是读操作A就不加锁,否则就加锁,哈哈,关键是A根本就不知道B会干什么,所以A要自保,所以读的时候也加上锁!
        至于性能,你可以从别的方面下手,比如优化整体的流程,架构。

大神们,我突然有一种想法,就是把指针弄成智能指针,这样无论是谁delete,只要还有别的地方已经获取了一份copy,那么就不会真正delete这个对象,那么也就不会出现p->DoSth();报错啦? 在p->DoSth();之后在delete p就行了。我是这样想的,不知道各位怎么看

引用 6 楼 holymaple 的回复:
Quote: 引用 1 楼 yangyunzhao 的回复:

读写锁
你测试过读写锁是性能瓶颈?还是臆想的?

引用 2 楼 fly_dragon_fly 的回复:

读写的并发程度很高吗

引用 3 楼 youjun610789338 的回复:

        在保证正确性的前提下再考虑性能,你光顾着性能的话,那写的时候也可以不用加锁啦
        读的时候不加锁,对于线程A来说是不负责任的,因为你没法控制系统的线程调度,除非此时线程B也是执行的读操作,那么你也许会想:可不可以对B的操作进行判断,如果是读操作A就不加锁,否则就加锁,哈哈,关键是A根本就不知道B会干什么,所以A要自保,所以读的时候也加上锁!
        至于性能,你可以从别的方面下手,比如优化整体的流程,架构。

大神们,我突然有一种想法,就是把指针弄成智能指针,这样无论是谁delete,只要还有别的地方已经获取了一份copy,那么就不会真正delete这个对象,那么也就不会出现p->DoSth();报错啦? 在p->DoSth();之后在delete p就行了。我是这样想的,不知道各位怎么看

且不说用智能指针能不能达到你要的效果,就算能达到,那修改操作呢?A在访问数据的同时,B把数据给修改了怎么办呢?

我倒是有个想法:可以参照MYSQL里的表级锁和行级锁来实现,按你的说法,map里的每对k/v对应的是主键/记录,那么可以试着在操作每条记录的时候上锁,而不是对整个map上锁,这样在操作第1000条记录的时候就不用等待第1条记录操作结束了。

你可以想先具体怎么实现行级锁,我试着想了一下实现方案,有点复杂,呵呵,mark一下,等有空了来搞搞!

20分
还是加锁比较安全吧
引用 7 楼 youjun610789338 的回复:
Quote: 引用 6 楼 holymaple 的回复:
Quote: 引用 1 楼 yangyunzhao 的回复:

读写锁
你测试过读写锁是性能瓶颈?还是臆想的?

引用 2 楼 fly_dragon_fly 的回复:

读写的并发程度很高吗

引用 3 楼 youjun610789338 的回复:

        在保证正确性的前提下再考虑性能,你光顾着性能的话,那写的时候也可以不用加锁啦
        读的时候不加锁,对于线程A来说是不负责任的,因为你没法控制系统的线程调度,除非此时线程B也是执行的读操作,那么你也许会想:可不可以对B的操作进行判断,如果是读操作A就不加锁,否则就加锁,哈哈,关键是A根本就不知道B会干什么,所以A要自保,所以读的时候也加上锁!
        至于性能,你可以从别的方面下手,比如优化整体的流程,架构。

大神们,我突然有一种想法,就是把指针弄成智能指针,这样无论是谁delete,只要还有别的地方已经获取了一份copy,那么就不会真正delete这个对象,那么也就不会出现p->DoSth();报错啦? 在p->DoSth();之后在delete p就行了。我是这样想的,不知道各位怎么看

且不说用智能指针能不能达到你要的效果,就算能达到,那修改操作呢?A在访问数据的同时,B把数据给修改了怎么办呢?

我倒是有个想法:可以参照MYSQL里的表级锁和行级锁来实现,按你的说法,map里的每对k/v对应的是主键/记录,那么可以试着在操作每条记录的时候上锁,而不是对整个map上锁,这样在操作第1000条记录的时候就不用等待第1条记录操作结束了。

你可以想先具体怎么实现行级锁,我试着想了一下实现方案,有点复杂,呵呵,mark一下,等有空了来搞搞!

哈哈,我本来也这样想,但觉得好像太复杂了就放弃了= =··· 有空搞一下

引用 8 楼 xmnathan 的回复:

还是加锁比较安全吧

唉,也是,还是加锁安全一些


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明map值为指针时多线程该怎么保护指针?
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!