C++ 关于无锁map的一些思考(线程安全)

前提

1、map 的 key 是可以穷举的

2、允许修改已经删除的 value,我们认为是创建了新 value 再修改

思路

1、先把所有的 key 放入 map 中,这里我们获取 key 的时候 100% 不会报错 (前提1)

key 永不删除,如果要删除 key,会体现在 value 上,见下文

2、value 值为原子变量,比如 c++ 有 atomic

atomic<int> flag = 0;

我们获取 value 的时候都是原子操作,不会和其他线程共享导致出问题

3、map 的 value 我们声明为一个特殊结构体(mapValue),包含两部分,一个为标记位,一个为真正的 value 值

struct mapValue{
	int flag;  // 标记位
	int value; // 真正的 value,可以是任意类型
};

4、标记位有两个状态,一个是删除状态,代表该值已经被删除;另外一个是可用状态,代表该 value 可以正常使用

使用方法如下

temp=m[key] //获取 map 的 key 对应的 value 时,务必请先拷贝至本地,temp 类型为 mapValue
if (temp.flag==1)
    // 如果到这里 m[key].flag 被改为 0 了,没有风险,因为我们有备份,最次也是读到脏数据
    value=temp.value
else
    //该key不存在,可能被删了

// 如果是下面这样可能会出问题 (没拷贝就直接使用)
if (m[key].flag==1)
    // 如果到这里 m[key].flag 被改为 0 了,就有风险,因为 m[key].value 可能会被连带修改
    value=m[key].value
else
    //该key不存在,可能被删了

mapValue 拷贝可以直接转成等长度的 char 数组结构体整体拷贝,比如

struct newMapValue{
	unsigned char[8] value;
};

修改和删除,就是新建 mapValue,然后再整体覆盖原有的 map 的 mapValue(前提2)

这样,无锁 map 的增删改查都没问题了

其他

1、如果要去除前提一的话,需要对 map 的桶原子化操作,因为我们知道,key 确定了,哈希 key 对应桶的位置也会确定,所以可以通过对桶原子化操作来避免线程不安全,但是这样会极大影响性能。并且这样以来会带来一个问题,就是 map 扩容会影响桶的元素,所以又会有新的限制,就是我们申请的 map 空间要足够大,避免 map 的扩容。前提一的存在,避免了上面说的情况。

2、前提二其实不是很影响使用,不去除没关系 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值