饭中淹的避难所~~~~~

偶尔来避难的地方~

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  94 随笔 :: 0 文章 :: 257 评论 :: 0 Trackbacks

volatile修饰,表示一个变量不进行寄存器优化,每次使用必须从内存中读取。

在两个线程间通信的时候,使用这个修饰,可以减少对锁的依赖。这意味着降低死锁的机会,提高效率。

我们假设存在两个线程,A和B。我们在A和B之间建立两条通道,A到B的通道和B到A的通道。

每个通道都有两个状态,当前有货和当前没货。这个状态用volatile来修饰,并确保它的写操作是原子操作

我们先考虑A到B的通道,考虑通一个,另一个通道就反方向建立起来就可以了。

在A到B的通道中:
  - A来检查通道的状态,是否是当前没货。如果是,就把货放到通道里,然后修改通道状态为当前有货。
  - B来检查通道的状态,是否是当前有货。如果是,就把货从通道里取出,然后修改通道状态为当前没货。

以上两个步骤因为是在A、B两个线程内同步进行的,所以没有标注顺序号。


用上面的步骤,不论货有多大,多么复杂。他们的读写操作都被这个修饰为volatile的状态给限制在他们应该在的那个线程。

通过分析,我们总结出一个无锁通信的结论:用volatile的状态检查和原子操作的状态修改,隔离数据读写。

虽然现在只是在两个线程间进行通信,不过这个结论,却可以应用到多个线程同时参与的环境。


posted on 2010-05-05 19:42 饭中淹 阅读(2289) 评论(11)  编辑 收藏 引用 所属分类: 数据算法分析

评论

# re: 无锁线程通信(1) 2010-05-05 20:25 shbooom
检查,置位是两个原子操作,所以还是不安全  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-05 21:05 饭中淹
@shbooom
不会,这是绝对安全的。
检查成功后,置位权就在自己手中了,所以不存在不安全的情况。
  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 09:23 fcc
无锁编程没这么简单吧?楼主你想象的情况太理想化了,A线程生产出来一个货物,接下来B线程就消费一个货物。可是当通道中已经有货还没消费掉,A线程又生产出来了怎么办?一、丢弃;二、等待B消费完当前货物,然后放入通道中;三、让通道货物为一个容器,通道状态依然在有货状态下A线程直接修改货物容器。都是有问题的。方法一不适应绝大多数需求。方法二意味着低效。方法三意味着有可能两个线程同时写一个容器,绝对线程不安全。如果容器本身是线程安全的,那倒也行。可是容器是线程安全的意味着锁在容器内部实现了,依然不是无锁编程。以上是我的考虑,如有不周,请指教。  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 10:32 饭中淹
@fcc
无锁编程确实没有这么简单。
这个例子,你仔细看每一句话,其实说的是你第二种方法。也就是互相等待的方法。低效是肯定的。
这个是第一部分,从简单的开始说起,慢慢的深入进去。
  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 11:27 爱饭盒
不是低效的问题,是仅一个标识位不能做到同步,要做到同步,需要指令支持检查置位做为一个原子操作。好像有cpu支持的。比如checkAndSet(flag)调用做为一个原子操作。否则就存在如下乱序。
if(A.check_flag() == 1 )
{
//线程A被挂起。
//线程B:if(B.check_flag() == 1) 此时也是为真,B.set_flag(0); 消耗掉资源,resource--;
//线程A被唤醒,
//线程A:A.set_flag(0);消耗资源. resource--;此时资源其实已经被消耗过了,A仍然可以去消耗。
//B.set_flag(1);
}
  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 12:13 饭中淹
@爱饭盒
请你认真看清楚,我就不解释了。  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 12:21 陈昱(CY)
那个通道状态“是否有货”实际就是锁,确实没有同步起来  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 12:33 小时候可靓了
嗯,这个方案还是可以滴。。
许多项目的源码里也有用到。。
但他们同样提供了带锁的方案。

估计这种简单的无锁有些局限,至于具体原因不知道。

先顶一个。希望你下一篇写得更高深!  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 12:49 bygreen
楼主最好实现个测试代码,测试通过才行  回复  更多评论
  

# re: 无锁线程通信(1)[未登录] 2010-05-06 13:25 cppexplore
如果不考虑线程wait和signal的问题,仅仅是读写问题,不加锁可行,我觉得前提是:
(1)只有两个线程参与,存在point_r 读指针和point_w 写指针 两个变量。
(2)只有读数据线程 写变量point_r , 只有写数据线程 写变量 point_w 。写就是一个变量的写操作只在一个线程内进行,其他线程只读。

原子性操作不能借助语言层面的volatile实现,必须借助基于硬件的基本原语完成。最近常说的lock_free编程,具体实现是spin_lock,基于CAS原语实现,是因为没有借助内核态的锁而著称。

  回复  更多评论
  

# re: 无锁线程通信(1) 2010-05-06 15:13 饭中淹
@cppexplore
本篇文章序号(1)  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理