- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
引言先抛开你所熟知的信号量、锁、同步原语等技术,思考这个问题:如何保证并发 读写的准确性? 一个没有任何并发编程经验的程序员可能会觉得很简单:这有什 么问题呢,同时读写能有什么问题,最多就是读到过期的数据而已。一个理想的 世界当然是这样,只可惜实际上的机器世界往往隐藏了很多不容易被发觉的事情。 至少有两个行为会影响这个结论:
?编译器往往有指令重排序的优化;例如程序员看到的源代码是好句以4;,
而实际上执行的顺序可能是以4;好3;,这是因为编译器为了优化执行效 率可能对指令进行重排序;
? 高级编程语言所支持的运算往往不是原子化的;例如a += 3实际上包含了
读变量、加运算和写变量三次原子操作。既然整个过程并不是原子化的,
就意味着随时有其它入侵者侵入修改数据。更为隐藏的例子:对于变量 的读写甚至可能都不是原子化的。不同机器读写变量的过程可能是不同的, 有些机器可能是64位数据一次性读写,而有些机器是32位数据一次读
写。这就意味着一个64位的数据在后者的读写上实际上是分成两次完成的!试想,如果你试图读取一个64位数据的值,先读取了低32的数据,
这时另一个线程切进来修改了整个数据的值,最后你再读取高32的值,
将高32和低32的数据拼成完整的值,很明显会得到一个预期以外的数 据。
看起来,整个并发编程的世界里一切都是不确定的,我们不知道每次读取的变量 到底是不是及时、准确的数据。幸运的是,很多语言都有一个kappehs-before的 规那么,能帮助我们在不确定的并发世界里寻找一丝确定性。
happens-before你可以把ka叩看作一种特殊的比拟运算,就好像〉、〈一样。对应的,
还有happe八s-aftec它们之间的关系也好像>、<一样:
Oncesync中还提供了一个。八cc的数据结构,用于控制并发编程中只执行一次的逻辑,
例如:
var a strii^gvair oince sg八八ccfeme setapO (
a = kelloj world11认土仇(set up11)
]fiAM do”int() {
o 八 ce.Do(s 血?)
fmt.Prmtfn(a))
Mac twopsMt。{
go dopHnt。
go dopHht。
)会打印 hello, world”两次和“set up”一次。。八”的happens-be- 规那么也很直观:
第一次执行。八ccQo happen-before其余的。八ceQo应用
掌握了上述的基本k即ins-bcf”c规那么,可以结合起来分析更复杂的场景了,来 看这个例子:
var a, b Mtfeme f() {
a = 1 // (I)
b = 2// (2))
心八cgO {
print(b) // ⑶
prii^t(a) // (4))
fiAAC kv\aii^0 {
go K)
gO)
这里⑴ka眸ChS-befC (2),⑶ka叩c八s-bcf”c(4),但是⑴与⑶、⑷之间以及⑵与 (3)、(4)之间并没有kappc八s-bcf”c关系,这时候结果是不确定的,一种有趣的结 果是2、0,也就是(1)、(2)之间发生了指令重排序。现在让我们修改一下上面的 代码,让它按我们预期的逻辑运行:要么打印0、0,要么打印1、2o使用锁
var a, b li^tvar lock Mutexfeme f(){
lock.LockQ // (2)
4二工〃(2)
b = 2 // ⑶
lock.Unlock() // (4))
心八c gO {
lock.LockO // ⑸
prii^t(b) // (6)
print⑷ // (7)
(ock.Un(ock() // (8))
八c kvxaiiaQ {
go fo
gO)
回想下锁的规那么:
1.对锁实例调用八次Unlock happ。八s-bcf。匕调用Lock作次,只要八<
这里,存在两种可能:要么(4) happens-before⑸,要么⑻happen -before⑴,会分 别推导出两种结果:⑹ happe八s-bcfc (7) happens-before (2) happens-before (3), 以及(2) happe八s-before ⑶ happens-befove (6) kappe八s-before (7),也就分别对应“0、 0〃和〃 1、2〃两种结果。
使用通道 var a, b iv^tvar c = i^ake(ck\a^ ict, 1) feme f() {
-c
4 = 1〃(2)
。= 2 // ⑶
c〈一1)
心八c gO {
-c
print(b) // (6)
prii^t(a) // (7)
c - 1)
八c testQ {
wg :二 sg八c.W?Mko〃?
文档评论(0)