-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch16-03-shared-state.html
136 lines (117 loc) · 49.8 KB
/
ch16-03-shared-state.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>共享状态并发</title>
<meta name="generator" content="VuePress 1.5.3">
<meta name="description" content="">
<link rel="preload" href="/assets/css/0.styles.12e35fbb.css" as="style"><link rel="preload" href="/assets/js/app.e6b14c5e.js" as="script"><link rel="preload" href="/assets/js/3.ecc21787.js" as="script"><link rel="preload" href="/assets/js/1.032ec45e.js" as="script"><link rel="preload" href="/assets/js/95.cc5ea7c4.js" as="script"><link rel="prefetch" href="/assets/js/10.0db432dd.js"><link rel="prefetch" href="/assets/js/100.1149107d.js"><link rel="prefetch" href="/assets/js/101.feae8ac2.js"><link rel="prefetch" href="/assets/js/102.4be35ad2.js"><link rel="prefetch" href="/assets/js/103.cb0bcc26.js"><link rel="prefetch" href="/assets/js/104.581a9df8.js"><link rel="prefetch" href="/assets/js/105.a5b31ce3.js"><link rel="prefetch" href="/assets/js/106.feb2cd4c.js"><link rel="prefetch" href="/assets/js/107.c74c3f7d.js"><link rel="prefetch" href="/assets/js/108.6a32c62d.js"><link rel="prefetch" href="/assets/js/109.3c3188fd.js"><link rel="prefetch" href="/assets/js/11.04463d2c.js"><link rel="prefetch" href="/assets/js/110.5f3f2327.js"><link rel="prefetch" href="/assets/js/111.374cf29b.js"><link rel="prefetch" href="/assets/js/112.37a66948.js"><link rel="prefetch" href="/assets/js/113.0e87d41d.js"><link rel="prefetch" href="/assets/js/114.e2641184.js"><link rel="prefetch" href="/assets/js/115.903cb5c3.js"><link rel="prefetch" href="/assets/js/116.d1cfad4c.js"><link rel="prefetch" href="/assets/js/117.ca412492.js"><link rel="prefetch" href="/assets/js/118.23919bb0.js"><link rel="prefetch" href="/assets/js/12.2de3af2e.js"><link rel="prefetch" href="/assets/js/13.69a23a33.js"><link rel="prefetch" href="/assets/js/14.3335c861.js"><link rel="prefetch" href="/assets/js/15.a469e71d.js"><link rel="prefetch" href="/assets/js/16.ee173d9e.js"><link rel="prefetch" href="/assets/js/17.959da5cf.js"><link rel="prefetch" href="/assets/js/18.0aa8fea6.js"><link rel="prefetch" href="/assets/js/19.21e6464d.js"><link rel="prefetch" href="/assets/js/20.b6d578fe.js"><link rel="prefetch" href="/assets/js/21.986be82f.js"><link rel="prefetch" href="/assets/js/22.47be6a63.js"><link rel="prefetch" href="/assets/js/23.15fe85eb.js"><link rel="prefetch" href="/assets/js/24.b3a04842.js"><link rel="prefetch" href="/assets/js/25.ae75ed87.js"><link rel="prefetch" href="/assets/js/26.643de6d4.js"><link rel="prefetch" href="/assets/js/27.6663d0a9.js"><link rel="prefetch" href="/assets/js/28.4669e096.js"><link rel="prefetch" href="/assets/js/29.65085b51.js"><link rel="prefetch" href="/assets/js/30.b4315895.js"><link rel="prefetch" href="/assets/js/31.e7ecf0dd.js"><link rel="prefetch" href="/assets/js/32.5d1db543.js"><link rel="prefetch" href="/assets/js/33.e8747222.js"><link rel="prefetch" href="/assets/js/34.852658b5.js"><link rel="prefetch" href="/assets/js/35.fa3f0352.js"><link rel="prefetch" href="/assets/js/36.8ebb5fa0.js"><link rel="prefetch" href="/assets/js/37.fa05856b.js"><link rel="prefetch" href="/assets/js/38.9aaa7af9.js"><link rel="prefetch" href="/assets/js/39.1a8b291e.js"><link rel="prefetch" href="/assets/js/4.f09c27b1.js"><link rel="prefetch" href="/assets/js/40.b9a756f6.js"><link rel="prefetch" href="/assets/js/41.7cef9fb3.js"><link rel="prefetch" href="/assets/js/42.04a2dfd5.js"><link rel="prefetch" href="/assets/js/43.b586e125.js"><link rel="prefetch" href="/assets/js/44.83db3147.js"><link rel="prefetch" href="/assets/js/45.e09151dc.js"><link rel="prefetch" href="/assets/js/46.f4d7d1f9.js"><link rel="prefetch" href="/assets/js/47.b935a8bb.js"><link rel="prefetch" href="/assets/js/48.10681e24.js"><link rel="prefetch" href="/assets/js/49.04036517.js"><link rel="prefetch" href="/assets/js/5.9229c7e7.js"><link rel="prefetch" href="/assets/js/50.385b0179.js"><link rel="prefetch" href="/assets/js/51.0a5c574d.js"><link rel="prefetch" href="/assets/js/52.5cd11b21.js"><link rel="prefetch" href="/assets/js/53.2efb9eb9.js"><link rel="prefetch" href="/assets/js/54.dd3a8f7d.js"><link rel="prefetch" href="/assets/js/55.e72498d3.js"><link rel="prefetch" href="/assets/js/56.5611b803.js"><link rel="prefetch" href="/assets/js/57.004dcc8a.js"><link rel="prefetch" href="/assets/js/58.de3a101d.js"><link rel="prefetch" href="/assets/js/59.a4d35b66.js"><link rel="prefetch" href="/assets/js/6.2ede05ad.js"><link rel="prefetch" href="/assets/js/60.ffa87f2b.js"><link rel="prefetch" href="/assets/js/61.c97c2157.js"><link rel="prefetch" href="/assets/js/62.1a964fd5.js"><link rel="prefetch" href="/assets/js/63.4fadefff.js"><link rel="prefetch" href="/assets/js/64.b0507c62.js"><link rel="prefetch" href="/assets/js/65.09fcdb27.js"><link rel="prefetch" href="/assets/js/66.c8f8a5cc.js"><link rel="prefetch" href="/assets/js/67.02fa33de.js"><link rel="prefetch" href="/assets/js/68.d49f848f.js"><link rel="prefetch" href="/assets/js/69.9dc909c1.js"><link rel="prefetch" href="/assets/js/7.00d72aac.js"><link rel="prefetch" href="/assets/js/70.e9702890.js"><link rel="prefetch" href="/assets/js/71.41a43a69.js"><link rel="prefetch" href="/assets/js/72.9f6f3145.js"><link rel="prefetch" href="/assets/js/73.64d032a1.js"><link rel="prefetch" href="/assets/js/74.6bb7d811.js"><link rel="prefetch" href="/assets/js/75.f9ddba21.js"><link rel="prefetch" href="/assets/js/76.ad390b83.js"><link rel="prefetch" href="/assets/js/77.bc150afb.js"><link rel="prefetch" href="/assets/js/78.69dc1271.js"><link rel="prefetch" href="/assets/js/79.5ce4cf53.js"><link rel="prefetch" href="/assets/js/8.f3a923c0.js"><link rel="prefetch" href="/assets/js/80.a9598d24.js"><link rel="prefetch" href="/assets/js/81.b1ca9b22.js"><link rel="prefetch" href="/assets/js/82.1017a114.js"><link rel="prefetch" href="/assets/js/83.d4fdce6e.js"><link rel="prefetch" href="/assets/js/84.f13715fe.js"><link rel="prefetch" href="/assets/js/85.af5497b5.js"><link rel="prefetch" href="/assets/js/86.07fb3684.js"><link rel="prefetch" href="/assets/js/87.d175c777.js"><link rel="prefetch" href="/assets/js/88.aa6d98dd.js"><link rel="prefetch" href="/assets/js/89.3d1bef74.js"><link rel="prefetch" href="/assets/js/9.3c7c9ecc.js"><link rel="prefetch" href="/assets/js/90.f46d49e9.js"><link rel="prefetch" href="/assets/js/91.6f0b514b.js"><link rel="prefetch" href="/assets/js/92.5a1abbdf.js"><link rel="prefetch" href="/assets/js/93.c50314c2.js"><link rel="prefetch" href="/assets/js/94.becb0d94.js"><link rel="prefetch" href="/assets/js/96.1ba1f23b.js"><link rel="prefetch" href="/assets/js/97.0436550a.js"><link rel="prefetch" href="/assets/js/98.180142a4.js"><link rel="prefetch" href="/assets/js/99.fa82e156.js">
<link rel="stylesheet" href="/assets/css/0.styles.12e35fbb.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container" data-v-dad8a512><div data-v-dad8a512><div id="loader-wrapper" class="loading-wrapper" data-v-d48f4d20 data-v-dad8a512 data-v-dad8a512><div class="loader-main" data-v-d48f4d20><div data-v-d48f4d20></div><div data-v-d48f4d20></div><div data-v-d48f4d20></div><div data-v-d48f4d20></div></div> <!----> <!----></div> <div class="password-shadow password-wrapper-out" style="display:none;" data-v-64685f0e data-v-dad8a512 data-v-dad8a512><h3 class="title" style="display:none;" data-v-64685f0e data-v-64685f0e></h3> <!----> <label id="box" class="inputBox" style="display:none;" data-v-64685f0e data-v-64685f0e><input type="password" value="" data-v-64685f0e> <span data-v-64685f0e>Konck! Knock!</span> <button data-v-64685f0e>OK</button></label> <div class="footer" style="display:none;" data-v-64685f0e data-v-64685f0e><span data-v-64685f0e><i class="iconfont reco-theme" data-v-64685f0e></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-64685f0e>vuePress-theme-reco</a></span> <span data-v-64685f0e><i class="iconfont reco-copyright" data-v-64685f0e></i> <a data-v-64685f0e><!---->
<!---->
2020
</a></span></div></div> <div class="hide" data-v-dad8a512><header class="navbar" data-v-dad8a512><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">Choose mode</h4> <ul class="color-mode-options"><li class="dark">dark</li><li class="auto active">auto</li><li class="light">light</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont undefined"></i>
回首页
</a></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-dad8a512></div> <aside class="sidebar" data-v-dad8a512><div class="personal-info-wrapper" data-v-ca798c94 data-v-dad8a512><!----> <!----> <div class="num" data-v-ca798c94><div data-v-ca798c94><h3 data-v-ca798c94>0</h3> <h6 data-v-ca798c94>Article</h6></div> <div data-v-ca798c94><h3 data-v-ca798c94>0</h3> <h6 data-v-ca798c94>Tag</h6></div></div> <hr data-v-ca798c94></div> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont undefined"></i>
回首页
</a></div> <!----></nav> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><a href="/title-page" class="sidebar-heading clickable open"><span>Rust 程序设计语言</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/foreword.html" class="sidebar-link">前言</a></li><li><a href="/ch00-00-introduction.html" class="sidebar-link">介绍</a></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch01-00-getting-started.html" class="sidebar-heading clickable"><span>1. 入门指南</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch01-01-installation.html" class="sidebar-link">1.1. 安装</a></li><li><a href="/ch01-02-hello-world.html" class="sidebar-link">1.2. Hello, World!</a></li><li><a href="/ch01-03-hello-cargo.html" class="sidebar-link">1.3. Hello, Cargo!</a></li></ul></section></li><li><a href="/ch02-00-guessing-game-tutorial.html" class="sidebar-link">2. 猜猜看游戏教程</a></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch03-00-common-programming-concepts.html" class="sidebar-heading clickable"><span>3. 常见编程概念</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch03-01-variables-and-mutability.html" class="sidebar-link">3.1. 变量与可变性</a></li><li><a href="/ch03-02-data-types.html" class="sidebar-link">3.2. 数据类型</a></li><li><a href="/ch03-03-how-functions-work.html" class="sidebar-link">3.3. 函数如何工作</a></li><li><a href="/ch03-04-comments.html" class="sidebar-link">3.4. 注释</a></li><li><a href="/ch03-05-control-flow.html" class="sidebar-link">3.5. 控制流</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch04-00-understanding-ownership.html" class="sidebar-heading clickable"><span>4. 认识所有权</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch04-01-what-is-ownership.html" class="sidebar-link">4.1. 什么是所有权?</a></li><li><a href="/ch04-02-references-and-borrowing.html" class="sidebar-link">4.2. 引用与借用</a></li><li><a href="/ch04-03-slices.html" class="sidebar-link">4.3. Slices</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch05-00-structs.html" class="sidebar-heading clickable"><span>5. 使用结构体来组织相关联的数据</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch05-01-defining-structs.html" class="sidebar-link">5.1. 定义并实例化结构体</a></li><li><a href="/ch05-02-example-structs.html" class="sidebar-link">5.2. 一个使用结构体的示例程序</a></li><li><a href="/ch05-03-method-syntax.html" class="sidebar-link">5.3. 方法语法</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch06-00-enums.html" class="sidebar-heading clickable"><span>6. 枚举与模式匹配</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch06-01-defining-an-enum.html" class="sidebar-link">6.1. 定义枚举</a></li><li><a href="/ch06-02-match.html" class="sidebar-link">6.2. match控制流运算符</a></li><li><a href="/ch06-03-if-let.html" class="sidebar-link">6.3. if let简洁控制流</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html" class="sidebar-heading clickable"><span>7. 使用包、Crate 和模块管理不断增长的项目</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch07-01-packages-and-crates.html" class="sidebar-link">7.1. 包和 crate</a></li><li><a href="/ch07-02-defining-modules-to-control-scope-and-privacy.html" class="sidebar-link">7.2. 定义模块来控制作用域与私有性</a></li><li><a href="/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html" class="sidebar-link">7.3. 路径用于引用模块树中的项</a></li><li><a href="/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html" class="sidebar-link">7.4. 使用use关键字将名称引入作用域</a></li><li><a href="/ch07-05-separating-modules-into-different-files.html" class="sidebar-link">7.5. 将模块分割进不同文件</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch08-00-common-collections.html" class="sidebar-heading clickable"><span>8. 常见集合</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch08-01-vectors.html" class="sidebar-link">8.1. vector</a></li><li><a href="/ch08-02-strings.html" class="sidebar-link">8.2. 字符串</a></li><li><a href="/ch08-03-hash-maps.html" class="sidebar-link">8.3. 哈希 map</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch09-00-error-handling.html" class="sidebar-heading clickable"><span>9. 错误处理</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch09-01-unrecoverable-errors-with-panic.html" class="sidebar-link">9.1. panic!与不可恢复的错误</a></li><li><a href="/ch09-02-recoverable-errors-with-result.html" class="sidebar-link">9.2. Result与可恢复的错误</a></li><li><a href="/ch09-03-to-panic-or-not-to-panic.html" class="sidebar-link">9.3. panic!还是不panic!</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch10-00-generics.html" class="sidebar-heading clickable"><span>10. 泛型、trait 与生命周期</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch10-01-syntax.html" class="sidebar-link">10.1. 泛型数据类型</a></li><li><a href="/ch10-02-traits.html" class="sidebar-link">10.2. trait:定义共享的行为</a></li><li><a href="/ch10-03-lifetime-syntax.html" class="sidebar-link">10.3. 生命周期与引用有效性</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch11-00-testing.html" class="sidebar-heading clickable"><span>11. 测试</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch11-01-writing-tests.html" class="sidebar-link">11.1. 编写测试</a></li><li><a href="/ch11-02-running-tests.html" class="sidebar-link">11.2. 运行测试</a></li><li><a href="/ch11-03-test-organization.html" class="sidebar-link">11.3. 测试的组织结构</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch12-00-an-io-project.html" class="sidebar-heading clickable"><span>12. 一个 I/O 项目:构建命令行程序</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch12-01-accepting-command-line-arguments.html" class="sidebar-link">12.1. 接受命令行参数</a></li><li><a href="/ch12-02-reading-a-file.html" class="sidebar-link">12.2. 读取文件</a></li><li><a href="/ch12-03-improving-error-handling-and-modularity.html" class="sidebar-link">12.3. 重构以改进模块化与错误处理</a></li><li><a href="/ch12-04-testing-the-librarys-functionality.html" class="sidebar-link">12.4. 采用测试驱动开发完善库的功能</a></li><li><a href="/ch12-05-working-with-environment-variables.html" class="sidebar-link">12.5. 处理环境变量</a></li><li><a href="/ch12-06-writing-to-stderr-instead-of-stdout.html" class="sidebar-link">12.6. 将错误信息输出到标准错误而不是标准输出</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch13-00-functional-features.html" class="sidebar-heading clickable"><span>13. Rust 中的函数式语言功能:迭代器与闭包</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch13-01-closures.html" class="sidebar-link">13.1. 闭包:可以捕获其环境的匿名函数</a></li><li><a href="/ch13-02-iterators.html" class="sidebar-link">13.2. 使用迭代器处理元素序列</a></li><li><a href="/ch13-03-improving-our-io-project.html" class="sidebar-link">13.3. 改进之前的 I/O 项目</a></li><li><a href="/ch13-04-performance.html" class="sidebar-link">13.4. 性能比较:循环对迭代器</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch14-00-more-about-cargo.html" class="sidebar-heading clickable"><span>14. 更多关于 Cargo 和 Crates.io 的内容</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch14-01-release-profiles.html" class="sidebar-link">14.1. 采用发布配置自定义构建</a></li><li><a href="/ch14-02-publishing-to-crates-io.html" class="sidebar-link">14.2. 将 crate 发布到 Crates.io</a></li><li><a href="/ch14-03-cargo-workspaces.html" class="sidebar-link">14.3. Cargo 工作空间</a></li><li><a href="/ch14-04-installing-binaries.html" class="sidebar-link">14.4. 使用cargo install从 Crates.io 安装二进制文件</a></li><li><a href="/ch14-05-extending-cargo.html" class="sidebar-link">14.5. Cargo 自定义扩展命令</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch15-00-smart-pointers.html" class="sidebar-heading clickable"><span>15. 智能指针</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch15-01-box.html" class="sidebar-link">15.1. Box<T>指向堆上数据,并且可确定大小</a></li><li><a href="/ch15-02-deref.html" class="sidebar-link">15.2. 通过Dereftrait 将智能指针当作常规引用处理</a></li><li><a href="/ch15-03-drop.html" class="sidebar-link">15.3. DropTrait 运行清理代码</a></li><li><a href="/ch15-04-rc.html" class="sidebar-link">15.4. Rc<T>引用计数智能指针</a></li><li><a href="/ch15-05-interior-mutability.html" class="sidebar-link">15.5. RefCell<T>与内部可变性模式</a></li><li><a href="/ch15-06-reference-cycles.html" class="sidebar-link">15.6. 引用循环与内存泄漏是安全的</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch16-00-concurrency.html" class="sidebar-heading clickable open"><span>16. 无畏并发</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch16-01-threads.html" class="sidebar-link">16.1. 线程</a></li><li><a href="/ch16-02-message-passing.html" class="sidebar-link">16.2. 消息传递</a></li><li><a href="/ch16-03-shared-state.html" aria-current="page" class="active sidebar-link">16.3. 共享状态</a></li><li><a href="/ch16-04-extensible-concurrency-sync-and-send.html" class="sidebar-link">16.4. 可扩展的并发:Sync与Send</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch17-00-oop.html" class="sidebar-heading clickable"><span>17. Rust 的面向对象编程特性</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch17-01-what-is-oo.html" class="sidebar-link">17.1. 面向对象语言的特点</a></li><li><a href="/ch17-02-trait-objects.html" class="sidebar-link">17.2. 为使用不同类型的值而设计的 trait 对象</a></li><li><a href="/ch17-03-oo-design-patterns.html" class="sidebar-link">17.3. 面向对象设计模式的实现</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch18-00-patterns.html" class="sidebar-heading clickable"><span>18. 模式用来匹配值的结构</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch18-01-all-the-places-for-patterns.html" class="sidebar-link">18.1. 所有可能会用到模式的位置</a></li><li><a href="/ch18-02-refutability.html" class="sidebar-link">18.2. Refutability:何时模式可能会匹配失败</a></li><li><a href="/ch18-03-pattern-syntax.html" class="sidebar-link">18.3. 模式的全部语法</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch19-00-advanced-features.html" class="sidebar-heading clickable"><span>19. 高级特征</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch19-01-unsafe-rust.html" class="sidebar-link">19.1. 不安全的 Rust</a></li><li><a href="/ch19-03-advanced-traits.html" class="sidebar-link">19.2. 高级 trait</a></li><li><a href="/ch19-04-advanced-types.html" class="sidebar-link">19.3. 高级类型</a></li><li><a href="/ch19-05-advanced-functions-and-closures.html" class="sidebar-link">19.4. 高级函数与闭包</a></li><li><a href="/ch19-06-macros.html" class="sidebar-link">19.5. 宏</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/ch20-00-final-project-a-web-server.html" class="sidebar-heading clickable"><span>20. 最后的项目: 构建多线程 web server</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/ch20-01-single-threaded.html" class="sidebar-link">20.1. 单线程 web server</a></li><li><a href="/ch20-02-multithreaded.html" class="sidebar-link">20.2. 将单线程 server 变为多线程 server</a></li><li><a href="/ch20-03-graceful-shutdown-and-cleanup.html" class="sidebar-link">20.3. 优雅停机与清理</a></li></ul></section></li><li><section class="sidebar-group is-sub-group depth-1"><a href="/appendix-00.html" class="sidebar-heading clickable"><span>21. 附录</span> <!----></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/appendix-01-keywords.html" class="sidebar-link">21.1. A - 关键字</a></li><li><a href="/appendix-02-operators.html" class="sidebar-link">21.2. B - 运算符与符号</a></li><li><a href="/appendix-03-derivable-traits.html" class="sidebar-link">21.3. C - 可派生的 trait</a></li><li><a href="/appendix-04-useful-development-tools.html" class="sidebar-link">21.4. D - 实用开发工具</a></li><li><a href="/appendix-05-editions.html" class="sidebar-link">21.5. E - 版本</a></li><li><a href="/appendix-06-translation.html" class="sidebar-link">21.6. F - 本书译本</a></li><li><a href="/appendix-07-nightly-rust.html" class="sidebar-link">21.7. G - Rust 是如何开发的与 “Nightly Rust”</a></li></ul></section></li></ul></section></li></ul> </aside> <div class="password-shadow password-wrapper-in" style="display:none;" data-v-64685f0e data-v-dad8a512><h3 class="title" style="display:none;" data-v-64685f0e data-v-64685f0e></h3> <!----> <label id="box" class="inputBox" style="display:none;" data-v-64685f0e data-v-64685f0e><input type="password" value="" data-v-64685f0e> <span data-v-64685f0e>Konck! Knock!</span> <button data-v-64685f0e>OK</button></label> <div class="footer" style="display:none;" data-v-64685f0e data-v-64685f0e><span data-v-64685f0e><i class="iconfont reco-theme" data-v-64685f0e></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-64685f0e>vuePress-theme-reco</a></span> <span data-v-64685f0e><i class="iconfont reco-copyright" data-v-64685f0e></i> <a data-v-64685f0e><!---->
<!---->
2020
</a></span></div></div> <div data-v-dad8a512><main class="page"><div class="page-title" style="display:none;"><h1>共享状态并发</h1> <div data-v-3b7f5bdf><!----> <!----> <!----> <!----></div></div> <div class="theme-reco-content content__default" style="display:none;"><h2 id="共享状态并发"><a href="#共享状态并发" class="header-anchor">#</a> 共享状态并发</h2> <blockquote><p><a href="https://github.com/rust-lang/book/blob/master/src/ch16-03-shared-state.md" target="_blank" rel="noopener noreferrer">ch16-03-shared-state.md<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> > <br>
commit ef072458f903775e91ea9e21356154bc57ee31da</p></blockquote> <p>虽然消息传递是一个很好的处理并发的方式,但并不是唯一一个。再一次思考一下 Go 编程语言文档中口号的这一部分:“不要通过共享内存来通讯”(“do not communicate by sharing memory.”):</p> <blockquote><p>What would communicating by sharing memory look like? In addition, why would message passing enthusiasts not use it and do the opposite instead?</p> <p>通过共享内存通讯看起来如何?除此之外,为何消息传递的拥护者并不使用它并反其道而行之呢?</p></blockquote> <p>在某种程度上,任何编程语言中的通道都类似于单所有权,因为一旦将一个值传送到通道中,将无法再使用这个值。共享内存类似于多所有权:多个线程可以同时访问相同的内存位置。第十五章介绍了智能指针如何使得多所有权成为可能,然而这会增加额外的复杂性,因为需要以某种方式管理这些不同的所有者。Rust 的类型系统和所有权规则极大的协助了正确地管理这些所有权。作为一个例子,让我们看看互斥器,一个更为常见的共享内存并发原语。</p> <h3 id="互斥器一次只允许一个线程访问数据"><a href="#互斥器一次只允许一个线程访问数据" class="header-anchor">#</a> 互斥器一次只允许一个线程访问数据</h3> <p><strong>互斥器</strong>(<em>mutex</em>)是 <em>mutual exclusion</em> 的缩写,也就是说,任意时刻,其只允许一个线程访问某些数据。为了访问互斥器中的数据,线程首先需要通过获取互斥器的 <strong>锁</strong>(<em>lock</em>)来表明其希望访问数据。锁是一个作为互斥器一部分的数据结构,它记录谁有数据的排他访问权。因此,我们描述互斥器为通过锁系统 <strong>保护</strong>(<em>guarding</em>)其数据。</p> <p>互斥器以难以使用著称,因为你不得不记住:</p> <ol><li>在使用数据之前尝试获取锁。</li> <li>处理完被互斥器所保护的数据之后,必须解锁数据,这样其他线程才能够获取锁。</li></ol> <p>作为一个现实中互斥器的例子,想象一下在某个会议的一次小组座谈会中,只有一个麦克风。如果一位成员要发言,他必须请求或表示希望使用麦克风。一旦得到了麦克风,他可以畅所欲言,然后将麦克风交给下一位希望讲话的成员。如果一位成员结束发言后忘记将麦克风交还,其他人将无法发言。如果对共享麦克风的管理出现了问题,座谈会将无法如期进行!</p> <p>正确的管理互斥器异常复杂,这也是许多人之所以热衷于通道的原因。然而,在 Rust 中,得益于类型系统和所有权,我们不会在锁和解锁上出错。</p> <h3 id="mutex-t-的-api"><a href="#mutex-t-的-api" class="header-anchor">#</a> <code>Mutex<T></code>的 API</h3> <p>作为展示如何使用互斥器的例子,让我们从在单线程上下文使用互斥器开始,如示例 16-12 所示:</p> <p><span class="filename">文件名: src/main.rs</span></p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token class-name">Mutex</span><span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> m <span class="token operator">=</span> <span class="token class-name">Mutex</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> num <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">*</span>num <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"m = {:?}"</span><span class="token punctuation">,</span> m<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><span class="caption">示例 16-12: 出于简单的考虑,在一个单线程上下文中探索 <code>Mutex<T></code> 的 API</span></p> <p>像很多类型一样,我们使用关联函数 <code>new</code> 来创建一个 <code>Mutex<T></code>。使用 <code>lock</code> 方法获取锁,以访问互斥器中的数据。这个调用会阻塞当前线程,直到我们拥有锁为止。</p> <p>如果另一个线程拥有锁,并且那个线程 panic 了,则 <code>lock</code> 调用会失败。在这种情况下,没人能够再获取锁,所以这里选择 <code>unwrap</code> 并在遇到这种情况时使线程 panic。</p> <p>一旦获取了锁,就可以将返回值(在这里是<code>num</code>)视为一个其内部数据的可变引用了。类型系统确保了我们在使用 <code>m</code> 中的值之前获取锁:<code>Mutex<i32></code> 并不是一个 <code>i32</code>,所以 <strong>必须</strong> 获取锁才能使用这个 <code>i32</code> 值。我们是不会忘记这么做的,因为反之类型系统不允许访问内部的 <code>i32</code> 值。</p> <p>正如你所怀疑的,<code>Mutex<T></code> 是一个智能指针。更准确的说,<code>lock</code> 调用 <strong>返回</strong> 一个叫做 <code>MutexGuard</code> 的智能指针。这个智能指针实现了 <code>Deref</code> 来指向其内部数据;其也提供了一个 <code>Drop</code> 实现当 <code>MutexGuard</code> 离开作用域时自动释放锁,这正发生于示例 16-12 内部作用域的结尾。为此,我们不会冒忘记释放锁并阻塞互斥器为其它线程所用的风险,因为锁的释放是自动发生的。</p> <p>丢弃了锁之后,可以打印出互斥器的值,并发现能够将其内部的 <code>i32</code> 改为 6。</p> <h4 id="在线程间共享-mutex-t"><a href="#在线程间共享-mutex-t" class="header-anchor">#</a> 在线程间共享 <code>Mutex<T></code></h4> <p>现在让我们尝试使用 <code>Mutex<T></code> 在多个线程间共享值。我们将启动十个线程,并在各个线程中对同一个计数器值加一,这样计数器将从 0 变为 10。示例 16-13 中的例子会出现编译错误,而我们将通过这些错误来学习如何使用 <code>Mutex<T></code>,以及 Rust 又是如何帮助我们正确使用的。</p> <p><span class="filename">文件名: src/main.rs</span></p> <div class="language-rust,ignore,does_not_compile extra-class"><pre class="language-text"><code>use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Mutex::new(0);
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
</code></pre></div><p><span class="caption">示例 16-13: 程序启动了 10 个线程,每个线程都通过 <code>Mutex<T></code> 来增加计数器的值</span></p> <p>这里创建了一个 <code>counter</code> 变量来存放内含 <code>i32</code> 的 <code>Mutex<T></code>,类似示例 16-12 那样。接下来遍历 range 创建了 10 个线程。使用了 <code>thread::spawn</code> 并对所有线程使用了相同的闭包:他们每一个都将调用 <code>lock</code> 方法来获取 <code>Mutex<T></code> 上的锁,接着将互斥器中的值加一。当一个线程结束执行,<code>num</code> 会离开闭包作用域并释放锁,这样另一个线程就可以获取它了。</p> <p>在主线程中,我们像示例 16-2 那样收集了所有的 join 句柄,调用它们的 <code>join</code> 方法来确保所有线程都会结束。这时,主线程会获取锁并打印出程序的结果。</p> <p>之前提示过这个例子不能编译,让我们看看为什么!</p> <div class="language-text extra-class"><pre class="language-text"><code>error[E0382]: use of moved value: `counter`
--> src/main.rs:9:36
|
9 | let handle = thread::spawn(move || {
| ^^^^^^^ value moved into closure here,
in previous iteration of loop
10 | let mut num = counter.lock().unwrap();
| ------- use occurs due to use in closure
|
= note: move occurs because `counter` has type `std::sync::Mutex<i32>`,
which does not implement the `Copy` trait
</code></pre></div><p>错误信息表明 <code>counter</code> 值在上一次循环中被移动了。所以 Rust 告诉我们不能将 <code>counter</code> 锁的所有权移动到多个线程中。让我们通过一个第十五章讨论过的多所有权手段来修复这个编译错误。</p> <h4 id="多线程和多所有权"><a href="#多线程和多所有权" class="header-anchor">#</a> 多线程和多所有权</h4> <p>在第十五章中,通过使用智能指针 <code>Rc<T></code> 来创建引用计数的值,以便拥有多所有者。让我们在这也这么做看看会发生什么。将示例 16-14 中的 <code>Mutex<T></code> 封装进 <code>Rc<T></code> 中并在将所有权移入线程之前克隆了 <code>Rc<T></code>。现在我们理解了所发生的错误,同时也将代码改回使用 <code>for</code> 循环,并保留闭包的 <code>move</code> 关键字:</p> <p><span class="filename">文件名: src/main.rs</span></p> <div class="language-rust,ignore,does_not_compile extra-class"><pre class="language-text"><code>use std::rc::Rc;
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Rc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Rc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
</code></pre></div><p><span class="caption">示例 16-14: 尝试使用 <code>Rc<T></code> 来允许多个线程拥有 <code>Mutex<T></code></span></p> <p>再一次编译并...出现了不同的错误!编译器真是教会了我们很多!</p> <div class="language-text extra-class"><pre class="language-text"><code>error[E0277]: `std::rc::Rc<std::sync::Mutex<i32>>` cannot be sent between threads safely
--> src/main.rs:11:22
|
11 | let handle = thread::spawn(move || {
| ^^^^^^^^^^^^^ `std::rc::Rc<std::sync::Mutex<i32>>`
cannot be sent between threads safely
|
= help: within `[closure@src/main.rs:11:36: 14:10
counter:std::rc::Rc<std::sync::Mutex<i32>>]`, the trait `std::marker::Send`
is not implemented for `std::rc::Rc<std::sync::Mutex<i32>>`
= note: required because it appears within the type
`[closure@src/main.rs:11:36: 14:10 counter:std::rc::Rc<std::sync::Mutex<i32>>]`
= note: required by `std::thread::spawn`
</code></pre></div><p>哇哦,错误信息太长不看!这里是一些需要注意的重要部分:第一行错误表明 <code>`std::rc::Rc<std::sync::Mutex<i32>>` cannot be sent between threads safely</code>。编译器也告诉了我们原因 <code>the trait bound `Send` is not satisfied</code>。下一部分会讲到 <code>Send</code>:这是确保所使用的类型可以用于并发环境的 trait 之一。</p> <p>不幸的是,<code>Rc<T></code> 并不能安全的在线程间共享。当 <code>Rc<T></code> 管理引用计数时,它必须在每一个 <code>clone</code> 调用时增加计数,并在每一个克隆被丢弃时减少计数。<code>Rc<T></code> 并没有使用任何并发原语,来确保改变计数的操作不会被其他线程打断。在计数出错时可能会导致诡异的 bug,比如可能会造成内存泄漏,或在使用结束之前就丢弃一个值。我们所需要的是一个完全类似 <code>Rc<T></code>,又以一种线程安全的方式改变引用计数的类型。</p> <h4 id="原子引用计数-arc-t"><a href="#原子引用计数-arc-t" class="header-anchor">#</a> 原子引用计数 <code>Arc<T></code></h4> <p>所幸 <code>Arc<T></code> <strong>正是</strong> 这么一个类似 <code>Rc<T></code> 并可以安全的用于并发环境的类型。字母 “a” 代表 <strong>原子性</strong>(<em>atomic</em>),所以这是一个<strong>原子引用计数</strong>(<em>atomically reference counted</em>)类型。原子性是另一类这里还未涉及到的并发原语:请查看标准库中 <code>std::sync::atomic</code> 的文档来获取更多细节。其中的要点就是:原子性类型工作起来类似原始类型,不过可以安全的在线程间共享。</p> <p>你可能会好奇为什么不是所有的原始类型都是原子性的?为什么不是所有标准库中的类型都默认使用 <code>Arc<T></code> 实现?原因在于线程安全带有性能惩罚,我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作,原子性提供的保证并无必要,代码可以因此运行的更快。</p> <p>回到之前的例子:<code>Arc<T></code> 和 <code>Rc<T></code> 有着相同的 API,所以修改程序中的 <code>use</code> 行和 <code>new</code> 调用。示例 16-15 中的代码最终可以编译和运行:</p> <p><span class="filename">文件名: src/main.rs</span></p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span>sync<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">Mutex</span><span class="token punctuation">,</span> <span class="token class-name">Arc</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">std<span class="token punctuation">::</span></span>thread<span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token class-name">Arc</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token class-name">Mutex</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> handles <span class="token operator">=</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> _ <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span><span class="token number">10</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token class-name">Arc</span><span class="token punctuation">::</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token operator">&</span>counter<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> handle <span class="token operator">=</span> <span class="token namespace">thread<span class="token punctuation">::</span></span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> <span class="token keyword">mut</span> num <span class="token operator">=</span> counter<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">*</span>num <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
handles<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>handle<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> handle <span class="token keyword">in</span> handles <span class="token punctuation">{</span>
handle<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token macro property">println!</span><span class="token punctuation">(</span><span class="token string">"Result: {}"</span><span class="token punctuation">,</span> <span class="token operator">*</span>counter<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p><span class="caption">示例 16-15: 使用 <code>Arc<T></code> 包装一个 <code>Mutex<T></code> 能够实现在多线程之间共享所有权</span></p> <p>这会打印出:</p> <div class="language-text extra-class"><pre class="language-text"><code>Result: 10
</code></pre></div><p>成功了!我们从 0 数到了 10,这可能并不是很显眼,不过一路上我们确实学习了很多关于 <code>Mutex<T></code> 和线程安全的内容!这个例子中构建的结构可以用于比增加计数更为复杂的操作。使用这个策略,可将计算分成独立的部分,分散到多个线程中,接着使用 <code>Mutex<T></code> 使用各自的结算结果更新最终的结果。</p> <h3 id="refcell-t-rc-t-与-mutex-t-arc-t-的相似性"><a href="#refcell-t-rc-t-与-mutex-t-arc-t-的相似性" class="header-anchor">#</a> <code>RefCell<T></code>/<code>Rc<T></code> 与 <code>Mutex<T></code>/<code>Arc<T></code> 的相似性</h3> <p>你可能注意到了,因为 <code>counter</code> 是不可变的,不过可以获取其内部值的可变引用;这意味着 <code>Mutex<T></code> 提供了内部可变性,就像 <code>Cell</code> 系列类型那样。正如第十五章中使用 <code>RefCell<T></code> 可以改变 <code>Rc<T></code> 中的内容那样,同样的可以使用 <code>Mutex<T></code> 来改变 <code>Arc<T></code> 中的内容。</p> <p>另一个值得注意的细节是 Rust 不能避免使用 <code>Mutex<T></code> 的全部逻辑错误。回忆一下第十五章使用 <code>Rc<T></code> 就有造成引用循环的风险,这时两个 <code>Rc<T></code> 值相互引用,造成内存泄漏。同理,<code>Mutex<T></code> 也有造成 <strong>死锁</strong>(<em>deadlock</em>) 的风险。这发生于当一个操作需要锁住两个资源而两个线程各持一个锁,这会造成它们永远相互等待。如果你对这个主题感兴趣,尝试编写一个带有死锁的 Rust 程序,接着研究任何其他语言中使用互斥器的死锁规避策略并尝试在 Rust 中实现他们。标准库中 <code>Mutex<T></code> 和 <code>MutexGuard</code> 的 API 文档会提供有用的信息。</p> <p>接下来,为了丰富本章的内容,让我们讨论一下 <code>Send</code>和 <code>Sync</code> trait 以及如何对自定义类型使用他们。</p></div> <footer class="page-edit" style="display:none;"><!----> <!----></footer> <!----> <!----> <!----></main> <!----></div></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div></div></div>
<script src="/assets/js/app.e6b14c5e.js" defer></script><script src="/assets/js/3.ecc21787.js" defer></script><script src="/assets/js/1.032ec45e.js" defer></script><script src="/assets/js/95.cc5ea7c4.js" defer></script>
</body>
</html>