├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── asyncwait ├── Cargo.toml └── src │ ├── async_trait_example.rs │ ├── asyncio.rs │ ├── future.rs │ ├── gat.rs │ ├── lib.rs │ ├── main.rs │ ├── monoio_example.rs │ └── runtimes.rs ├── channel ├── Cargo.toml └── src │ ├── lib.rs │ ├── main.rs │ └── others.rs ├── collections ├── Cargo.toml └── src │ ├── lib.rs │ └── main.rs ├── container_primitive ├── Cargo.toml └── src │ ├── box.rs │ ├── cell.rs │ ├── cow.rs │ ├── lib.rs │ ├── main.rs │ └── rc.rs ├── crossbeam_examples ├── Cargo.toml └── src │ ├── atomics.rs │ ├── collections.rs │ ├── lib.rs │ ├── main.rs │ ├── primitives.rs │ └── util.rs ├── parking_lot_examples ├── Cargo.toml └── src │ ├── customized_lock.rs │ ├── lib.rs │ └── main.rs ├── pool ├── Cargo.toml └── src │ ├── lib.rs │ └── main.rs ├── process ├── Cargo.toml └── src │ ├── lib.rs │ └── main.rs ├── rayon_examples ├── Cargo.toml └── src │ ├── lib.rs │ └── main.rs ├── special ├── Cargo.toml └── src │ ├── arcswap.rs │ ├── lib.rs │ ├── main.rs │ ├── map.rs │ ├── notify.rs │ ├── oneshots.rs │ ├── oslock.rs │ ├── primitive │ ├── async_lock_examples.rs │ ├── atomic_examples.rs │ ├── atomic_waker_examples.rs │ ├── mod.rs │ ├── sharded_slab_example.rs │ ├── simple_mutex_examples.rs │ ├── try_lock_examples.rs │ └── waitgroup_examples.rs │ ├── queue.rs │ ├── scc_examples.rs │ ├── sema_examples.rs │ ├── singleflight_example.rs │ └── synccow.rs ├── sync_primitive ├── Cargo.toml └── src │ ├── arc.rs │ ├── atomic.rs │ ├── barrier.rs │ ├── cond.rs │ ├── exclusive.rs │ ├── lazy.rs │ ├── lib.rs │ ├── main.rs │ ├── mpsc.rs │ ├── mutex.rs │ ├── once.rs │ └── rwlock.rs ├── thread ├── .gitignore ├── Cargo.toml └── src │ ├── lib.rs │ ├── main.rs │ └── threads.rs ├── timer_examples ├── Cargo.toml └── src │ ├── lib.rs │ ├── main.rs │ ├── tickers.rs │ └── timers.rs └── tokio_examples ├── Cargo.toml └── src ├── lib.rs ├── main.rs └── primitives.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | .history -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["thread", "pool", "asyncwait", "container_primitive", "sync_primitive", "collections", "process", "channel", "timer_examples", "parking_lot_examples", "crossbeam_examples", "rayon_examples", "tokio_examples", "special"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # concurrency programming via rust 2 | 3 | ![](book/images/gear.png) 4 | 5 | ## How to run? 6 | 7 | Enter one crate such as thread and run `cargo run`. 8 | 9 | ## Contents 10 | 11 | I have a plan to write a book about conncurrency programming via rust. The below is the contents of it and this repo contains all source codes. 12 | 13 | ### chapter 1: Thread 14 | 15 | Introduces [Threads](thread/src/main.rs) in std and concurrency libs. 16 | 17 | 18 | ### chapter 2: Thread Pool 19 | 20 | Introduces [Thread pool](pool/src/main.rs) for std thread. 21 | 22 | ### chapter 3: async/await 23 | 24 | Introduces [async feature](asyncwait/src/main.rs). 25 | 26 | ### chapter 4: synchronization primitives 27 | 28 | Introduces synchronization primitives contains [containers](container_primitive/src/main.rs) 29 | 30 | ### chapter 5: basic concurrency primitives 31 | Introduction of basic concurrency [primitives](sync_primitive/src/main.rs) in std lib. 32 | 33 | ### chapter 6: concurrency collections 34 | 35 | Introduces [concurrency collections](collections/src/main.rs) in std lib. 36 | 37 | ### chapter 7: process 38 | 39 | Introduces starting and executing a new [process](process/src/main.rs) in the easy way. 40 | 41 | ### chapter 8: channel 42 | 43 | Introduces each [channels](channel/src/main.rs) such as mpsc, mpmc and broadcasters. 44 | 45 | ### chapter 9: timer/ticker 46 | 47 | Introduces [timer and ticker](timer_examples/src/main.rs). 48 | 49 | ### chapter 10: parking_lot 50 | 51 | Introduces [parking_lot](parking_lot_examples/src/main.rs). 52 | 53 | ### chapter 11: crossbeam 54 | 55 | Introduces [crossbeam](crossbeam_examples/src/main.rs). 56 | 57 | ### chapter 12: rayon 58 | 59 | Introduces [rayon](rayon_examples/src/main.rs). 60 | 61 | ### chapter 13: tokio 62 | 63 | Introduces [tokio](tokio_examples/src/main.rs). 64 | 65 | ### chapter 14: special 66 | 67 | some special synchronization primitives and concurrency libs only for special single purpose. 68 | 69 | 70 | - replace std::mpsc with crossbeam-channel: https://github.com/rust-lang/rust/pull/93563 -------------------------------------------------------------------------------- /asyncwait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "asyncwait" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.65" 10 | async-std = "1.12.0" 11 | async-stream = "0.3.3" 12 | async-trait = "0.1.57" 13 | bytes = "1.2.1" 14 | futures = { version = "0.3.24", features = ["executor", "thread-pool"] } 15 | futures-lite = "1.12.0" 16 | futures-util = "0.3.24" 17 | monoio = "0.1.9" 18 | smol = "1.2.5" 19 | tokio = { version = "1.21.2", features = ["full"] } 20 | value-bag = "1.4.1" 21 | -------------------------------------------------------------------------------- /asyncwait/src/async_trait_example.rs: -------------------------------------------------------------------------------- 1 | use async_trait::*; // the official feature is not stable yet 2 | 3 | // https://blog.theincredibleholk.org/blog/2022/04/18/how-async-functions-in-traits-could-work-in-rustc/ 4 | 5 | #[async_trait] 6 | trait AsyncTrait { 7 | async fn get_string(&self) -> String; 8 | } 9 | 10 | #[async_trait] 11 | impl AsyncTrait for i32 { 12 | async fn get_string(&self) -> String { 13 | self.to_string() 14 | } 15 | } 16 | 17 | pub fn async_trait_example() { 18 | let rt = tokio::runtime::Runtime::new().unwrap(); 19 | rt.block_on(async { 20 | let x = 10; 21 | let y = x.get_string().await; 22 | println!("y={}", y); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /asyncwait/src/asyncio.rs: -------------------------------------------------------------------------------- 1 | use async_stream::stream; 2 | 3 | use futures_util::pin_mut; 4 | use futures_util::stream::StreamExt; 5 | use futures_lite::AsyncReadExt; 6 | 7 | pub fn stream() { 8 | futures_lite::future::block_on(async { 9 | let s = stream! { 10 | for i in 0..3 { 11 | yield i; 12 | } 13 | }; 14 | 15 | pin_mut!(s); // needed for iteration 16 | 17 | while let Some(value) = s.next().await { 18 | println!("got {}", value); 19 | } 20 | }); 21 | } 22 | 23 | pub fn futures_lite_io(){ 24 | futures_lite::future::block_on(async { 25 | let input: &[u8] = b"hello"; 26 | let mut reader = futures_lite::io::BufReader::new(input); 27 | 28 | let mut contents = String::new(); 29 | reader.read_to_string(&mut contents).await.unwrap(); 30 | }); 31 | 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /asyncwait/src/future.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::Arc; 3 | use std::sync::Mutex; 4 | use std::task::Waker; 5 | use std::task::Poll; 6 | use std::task::Context; 7 | use std::time::Duration; 8 | use std::thread; 9 | use std::future::Future; 10 | use std::pin::Pin; 11 | 12 | 13 | pub struct TimerFuture { 14 | shared_state: Arc>, 15 | } 16 | 17 | /// Shared state between the future and the waiting thread 18 | struct SharedState { 19 | completed: bool, 20 | waker: Option, 21 | } 22 | 23 | impl TimerFuture { 24 | pub fn new(duration: Duration) -> TimerFuture { 25 | let shared_state = Arc::new(Mutex::new(SharedState { 26 | completed: false, 27 | waker: None, 28 | })); 29 | 30 | let thread_shared_state = shared_state.clone(); 31 | 32 | thread::spawn(move || { 33 | thread::sleep(duration); 34 | let mut shared_state = thread_shared_state.lock().unwrap(); 35 | 36 | shared_state.completed = true; 37 | if let Some(waker) = shared_state.waker.take() { 38 | waker.wake(); 39 | } 40 | }); 41 | 42 | TimerFuture { shared_state } 43 | } 44 | } 45 | 46 | impl Future for TimerFuture { 47 | type Output = (); 48 | 49 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 50 | let mut shared_state = self.shared_state.lock().unwrap(); 51 | 52 | if shared_state.completed { 53 | println!("TimerFuture completed"); 54 | Poll::Ready(()) 55 | } else { 56 | shared_state.waker = Some(cx.waker().clone()); 57 | Poll::Pending 58 | } 59 | } 60 | } 61 | 62 | pub fn timefuture_async() { 63 | let tf = TimerFuture::new(Duration::from_millis(1000)); 64 | smol::block_on(tf) 65 | } -------------------------------------------------------------------------------- /asyncwait/src/gat.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use async_std::io::WriteExt; 3 | use bytes::Bytes; 4 | 5 | // copy from https://www.sobyte.net/post/2022-04/rust-gat-async-trait/ 6 | // 7 | // generic_associated_types 8 | // type_alias_impl_trait traits 9 | pub trait KvIterator { 10 | type NextFuture<'a>: Future> 11 | where 12 | Self: 'a; 13 | 14 | /// Get the next item from the iterator. 15 | fn next(&mut self) -> Self::NextFuture<'_>; 16 | } 17 | 18 | pub struct TestIterator { 19 | idx: usize, 20 | to_idx: usize, 21 | key: Vec, 22 | value: Vec, 23 | } 24 | 25 | impl TestIterator { 26 | pub fn new(from_idx: usize, to_idx: usize) -> Self { 27 | Self { 28 | idx: from_idx, 29 | to_idx, 30 | key: Vec::new(), 31 | value: Vec::new(), 32 | } 33 | } 34 | } 35 | 36 | #[allow(deprecated_where_clause_location)] 37 | impl KvIterator for TestIterator { 38 | type NextFuture<'a> 39 | where 40 | Self: 'a, 41 | = impl Future>; 42 | 43 | fn next(&mut self) -> Self::NextFuture<'_> { 44 | async move { 45 | if self.idx >= self.to_idx { 46 | return None; 47 | } 48 | 49 | // Zero-allocation key value manipulation 50 | 51 | self.key.clear(); 52 | 53 | write!(&mut self.key, "key_{:05}", self.idx).await.unwrap(); 54 | 55 | self.value.clear(); 56 | write!(&mut self.value, "value_{:05}", self.idx).await.unwrap(); 57 | 58 | self.idx += 1; 59 | Some((&self.key[..], &self.value[..])) 60 | } 61 | } 62 | } 63 | 64 | pub fn kviterator_example() { 65 | let rt = tokio::runtime::Runtime::new().unwrap(); 66 | rt.block_on(async { 67 | let mut iter = TestIterator::new(0, 10); 68 | while let Some((key, value)) = iter.next().await { 69 | println!( 70 | "{:?} {:?}", 71 | Bytes::copy_from_slice(key), 72 | Bytes::copy_from_slice(value) 73 | ); 74 | } 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /asyncwait/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(type_alias_impl_trait)] 2 | #![feature(impl_trait_in_assoc_type)] 3 | 4 | 5 | // #![feature(return_position_impl_trait_in_trait)] 6 | 7 | mod asyncio; 8 | mod future; 9 | mod runtimes; 10 | mod gat; 11 | mod async_trait_example; 12 | mod monoio_example; 13 | 14 | pub use asyncio::*; 15 | pub use future::*; 16 | pub use runtimes::*; 17 | pub use gat::*; 18 | pub use async_trait_example::*; 19 | pub use monoio_example::*; 20 | 21 | 22 | -------------------------------------------------------------------------------- /asyncwait/src/main.rs: -------------------------------------------------------------------------------- 1 | use asyncwait::*; 2 | 3 | fn main() { 4 | tokio_async(); 5 | futures_async(); 6 | futures_lite_async(); 7 | async_std(); 8 | async_std_task(); 9 | smol_async(); 10 | 11 | timefuture_async(); 12 | 13 | try_join(); 14 | join(); 15 | select(); 16 | futures_select(); 17 | smol_zip(); 18 | 19 | stream(); 20 | 21 | kviterator_example(); 22 | 23 | async_trait_example(); 24 | 25 | match monoio_example() { 26 | Ok(_) => println!("monoio_example: Ok"), 27 | Err(e) => println!("monoio_example: Err: {}", e), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /asyncwait/src/monoio_example.rs: -------------------------------------------------------------------------------- 1 | 2 | use monoio::fs::File; 3 | 4 | 5 | pub fn monoio_example() -> Result<(), Box>{ 6 | monoio::start::(async { 7 | println!("monoio_example: Hello world!"); 8 | 9 | // Open a file 10 | let file = File::open("LICENSE").await?; 11 | 12 | let buf = vec![0; 4096]; 13 | // Read some data, the buffer is passed by ownership and 14 | // submitted to the kernel. When the operation completes, 15 | // we get the buffer back. 16 | let (res, buf) = file.read_at(buf, 0).await; 17 | let n = res?; 18 | 19 | // Display the contents 20 | println!("monoio_example: {:?}", &buf[..n]); 21 | 22 | Ok(()) 23 | }) 24 | } 25 | 26 | -------------------------------------------------------------------------------- /asyncwait/src/runtimes.rs: -------------------------------------------------------------------------------- 1 | use futures::channel::mpsc; 2 | use futures::executor::{self, ThreadPool}; 3 | use futures::try_join; 4 | use futures::StreamExt; 5 | use futures::{ 6 | future::FutureExt, // for `.fuse()` 7 | join, 8 | pin_mut, 9 | select, 10 | }; 11 | 12 | use async_std::task; 13 | 14 | pub fn tokio_async() { 15 | let rt = tokio::runtime::Runtime::new().unwrap(); 16 | rt.block_on(async { 17 | println!("Hello from tokio!"); 18 | 19 | rt.spawn(async { 20 | println!("Hello from a tokio task!"); 21 | println!("in spawn") 22 | }) 23 | .await 24 | .unwrap(); 25 | }); 26 | 27 | rt.spawn_blocking(|| println!("in spawn_blocking")); 28 | } 29 | 30 | pub fn futures_async() { 31 | let pool = ThreadPool::new().expect("Failed to build pool"); 32 | let (tx, rx) = mpsc::unbounded::(); 33 | 34 | let fut_values = async { 35 | let fut_tx_result = async move { 36 | (0..100).for_each(|v| { 37 | tx.unbounded_send(v).expect("Failed to send"); 38 | }) 39 | }; 40 | pool.spawn_ok(fut_tx_result); 41 | 42 | let fut_values = rx.map(|v| v * 2).collect(); 43 | 44 | fut_values.await 45 | }; 46 | 47 | let values: Vec = executor::block_on(fut_values); 48 | 49 | println!("Values={:?}", values); 50 | } 51 | 52 | pub fn futures_lite_async() { 53 | futures_lite::future::block_on(async { println!("Hello from futures_lite") }) 54 | } 55 | 56 | pub fn async_std() { 57 | async_std::task::block_on(async { println!("Hello from async_std") }) 58 | } 59 | 60 | pub fn async_std_task() { 61 | task::block_on(async { 62 | task::spawn(get_book()); 63 | task::spawn(get_music()); 64 | 65 | println!("in async_std_task"); 66 | }); 67 | } 68 | 69 | pub fn smol_async() { 70 | smol::block_on(async { println!("Hello from smol") }); 71 | } 72 | 73 | #[derive(Debug)] 74 | struct Book(); 75 | #[derive(Debug)] 76 | struct Music(); 77 | 78 | async fn get_book() -> Result { 79 | println!("in get_book"); 80 | Ok(Book()) 81 | } 82 | async fn get_music() -> Result { 83 | println!("in get_music"); 84 | Ok(Music()) 85 | } 86 | 87 | pub fn try_join() { 88 | futures_lite::future::block_on(async { 89 | let book_fut = get_book(); 90 | let music_fut = get_music(); 91 | println!("try_join: {:?}", try_join!(book_fut, music_fut)); 92 | }); 93 | } 94 | 95 | pub fn join() { 96 | let a = async { 1 }; 97 | let b = async { 2 }; 98 | let c = async { 3 }; 99 | 100 | futures_lite::future::block_on(async { 101 | println!("join: {:?}", join!(get_book(), get_music())); 102 | println!("join: {:?}", join!(a, b, c)); 103 | }); 104 | } 105 | 106 | pub fn select() { 107 | futures_lite::future::block_on(async { 108 | let t1 = get_book().fuse(); 109 | let t2 = get_music().fuse(); 110 | 111 | pin_mut!(t1, t2); 112 | 113 | select! { 114 | _x = t1 => println!("select get_book"), 115 | _y = t2 => println!("select get_music"), 116 | } 117 | }); 118 | } 119 | 120 | pub fn futures_select() { 121 | futures_lite::future::block_on(async { 122 | use futures::future; 123 | 124 | let mut a_fut = future::ready(4); 125 | let mut b_fut = future::ready(6); 126 | let mut total = 0; 127 | 128 | loop { 129 | select! { 130 | a = a_fut => total += a, 131 | b = b_fut => total += b, 132 | complete => {println!("complete"); break}, 133 | default => unreachable!(), // never runs (futures are ready, then complete) 134 | }; 135 | } 136 | assert_eq!(total, 10); 137 | }); 138 | } 139 | 140 | pub fn smol_zip() { 141 | smol::block_on(async { 142 | use smol::future::{try_zip, zip}; 143 | 144 | let future1 = async { 1 }; 145 | let future2 = async { 2 }; 146 | 147 | let result = zip(future1, future2); 148 | println!("smol_zip: {:?}", result.await); 149 | 150 | let future1 = async { Ok::(1) }; 151 | let future2 = async { Err::(2) }; 152 | 153 | let result = try_zip(future1, future2).await; 154 | println!("smol_try_zip: {:?}", result); 155 | }); 156 | } 157 | -------------------------------------------------------------------------------- /channel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "channel" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-channel = "1.7.1" 10 | async-priority-channel = "0.1.0" 11 | broadcaster = "1.0.0" 12 | crossfire = "0.1.7" 13 | flume = "0.10.14" 14 | futures = "0.3.24" 15 | futures-channel = "0.3.24" 16 | futures-util = "0.3.24" 17 | kanal = "0.1.0-pre6" 18 | tokio = { version = "1.21.2", features = ["full"] } 19 | -------------------------------------------------------------------------------- /channel/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod others; 2 | pub use others::*; 3 | 4 | use std::sync::mpsc; 5 | use std::sync::mpsc::sync_channel; 6 | use std::thread; 7 | use std::time::Duration; 8 | 9 | pub fn mpsc_example1() { 10 | let (tx, rx) = mpsc::channel(); 11 | 12 | thread::spawn(move || { 13 | let val = String::from("hi"); 14 | tx.send(val).unwrap(); 15 | // println!("val is {}", val); 16 | }); 17 | 18 | let received = rx.recv().unwrap(); 19 | println!("Got: {}", received); 20 | } 21 | 22 | pub fn mpsc_example2() { 23 | let (tx, rx) = mpsc::channel(); 24 | for i in 0..10 { 25 | let tx = tx.clone(); 26 | thread::spawn(move || { 27 | tx.send(i).unwrap(); 28 | }); 29 | } 30 | 31 | for _ in 0..10 { 32 | let j = rx.recv().unwrap(); 33 | println!("Got: {}", j); 34 | } 35 | } 36 | 37 | pub fn mpsc_example3() { 38 | let (tx, rx) = sync_channel::(0); 39 | thread::spawn(move || { 40 | // This will wait for the parent thread to start receiving 41 | tx.send(53).unwrap(); 42 | }); 43 | rx.recv().unwrap(); 44 | } 45 | 46 | pub fn mpsc_example4() { 47 | let (tx, rx) = sync_channel(3); 48 | 49 | for _ in 0..3 { 50 | let tx = tx.clone(); 51 | // cloned tx dropped within thread 52 | thread::spawn(move || tx.send("ok").unwrap()); 53 | } 54 | 55 | drop(tx); 56 | 57 | // Unbounded receiver waiting for all senders to complete. 58 | while let Ok(msg) = rx.recv() { 59 | println!("{msg}"); 60 | } 61 | 62 | println!("mpsc_example4 completed"); 63 | } 64 | 65 | pub fn mpsc_drop_example() { 66 | // 创建一个有边界的多生产者、单消费者的通道 67 | let (sender, receiver) = mpsc::channel::(); // 指定通道中传递的数据类型为 i32 68 | 69 | // 启动三个生产者线程 70 | for i in 0..3 { 71 | let tx = sender.clone(); // 克隆发送端,每个线程都拥有独立的发送端 72 | thread::spawn(move || { 73 | thread::sleep(Duration::from_secs(1)); // 等待所有线程启动完毕 74 | tx.send(i).expect("Failed to send message"); 75 | }); 76 | } 77 | 78 | 79 | // 丢弃发送端,不影响clone 80 | drop(sender); 81 | 82 | 83 | // 主线程作为消费者,接收来自生产者线程的消息 84 | for received_message in receiver { 85 | println!("Received message: {}", received_message); 86 | } 87 | } -------------------------------------------------------------------------------- /channel/src/main.rs: -------------------------------------------------------------------------------- 1 | use channel::*; 2 | 3 | fn main() { 4 | mpsc_example1(); 5 | mpsc_example2(); 6 | mpsc_example3(); 7 | mpsc_example4(); 8 | mpsc_drop_example(); 9 | 10 | crossfire_mpsc(); 11 | crossfire_mpmc(); 12 | 13 | flume_example(); 14 | flume_select(); 15 | flume_async(); 16 | 17 | async_channel_example(); 18 | async_priority_channel_example(); 19 | futures_channel_mpsc_example(); 20 | futures_channel_oneshot_example(); 21 | kanal_example(); 22 | kanal_async_example(); 23 | kanal_oneshot_example(); 24 | } 25 | -------------------------------------------------------------------------------- /channel/src/others.rs: -------------------------------------------------------------------------------- 1 | use crossfire::mpmc; 2 | use crossfire::mpsc; 3 | use flume; 4 | 5 | use std::thread; 6 | 7 | pub fn crossfire_mpsc() { 8 | let rt = tokio::runtime::Runtime::new().unwrap(); 9 | 10 | let (tx, rx) = mpsc::bounded_future_both::(100); 11 | 12 | rt.block_on(async move { 13 | tokio::spawn(async move { 14 | for i in 0i32..10 { 15 | let _ = tx.send(i).await; 16 | println!("sent {}", i); 17 | } 18 | }); 19 | 20 | loop { 21 | if let Ok(_i) = rx.recv().await { 22 | println!("recv {}", _i); 23 | } else { 24 | println!("rx closed"); 25 | break; 26 | } 27 | } 28 | }); 29 | } 30 | 31 | pub fn crossfire_mpmc() { 32 | let rt = tokio::runtime::Runtime::new().unwrap(); 33 | 34 | let (tx, rx) = mpmc::bounded_future_both::(100); 35 | 36 | rt.block_on(async move { 37 | let mut sender_handles = vec![]; 38 | 39 | for _ in 0..4 { 40 | let tx = tx.clone(); 41 | let handle = tokio::spawn(async move { 42 | for i in 0i32..10 { 43 | let _ = tx.send(i).await; 44 | println!("sent {}", i); 45 | } 46 | }); 47 | sender_handles.push(handle); 48 | } 49 | 50 | let mut handles = vec![]; 51 | for i in 0..4 { 52 | let rx = rx.clone(); 53 | let handle = tokio::spawn(async move { 54 | loop { 55 | if let Ok(_i) = rx.recv().await { 56 | println!("thread {} recv {}", i, _i); 57 | } else { 58 | println!("rx closed"); 59 | break; 60 | } 61 | } 62 | }); 63 | handles.push(handle); 64 | } 65 | 66 | for handle in sender_handles { 67 | handle.await.unwrap(); 68 | } 69 | drop(tx); 70 | 71 | for handle in handles { 72 | handle.await.unwrap(); 73 | } 74 | }); 75 | } 76 | 77 | // has issues. 78 | pub fn broadcaster() { 79 | // let rt = tokio::runtime::Runtime::new().unwrap(); 80 | 81 | // let mut chan = BroadcastChannel::new(); 82 | // rt.block_on(async move { 83 | // chan.send(&5i32).await.unwrap(); 84 | // println!("chan: {}", chan.next().await.unwrap()); 85 | 86 | // let chan2 = chan.clone(); 87 | // chan2.send(&6i32).await.unwrap(); 88 | 89 | // println!("chan1: {}", chan.next().await.unwrap()); 90 | // println!("chan2: {}", chan.next().await.unwrap()); 91 | // }); 92 | } 93 | 94 | pub fn flume_example() { 95 | let (tx, rx) = flume::unbounded(); 96 | 97 | thread::spawn(move || { 98 | (0..10).for_each(|i| { 99 | tx.send(i).unwrap(); 100 | }) 101 | }); 102 | 103 | let received: u32 = rx.iter().sum(); 104 | 105 | assert_eq!((0..10).sum::(), received); 106 | } 107 | 108 | pub fn flume_select() { 109 | let (tx0, rx0) = flume::unbounded(); 110 | let (tx1, rx1) = flume::unbounded(); 111 | 112 | std::thread::spawn(move || { 113 | tx0.send(true).unwrap(); 114 | tx1.send(42).unwrap(); 115 | }); 116 | 117 | flume::Selector::new() 118 | .recv(&rx0, |b| println!("Received {:?}", b)) 119 | .recv(&rx1, |n| println!("Received {:?}", n)) 120 | .wait(); 121 | } 122 | 123 | pub fn flume_async() { 124 | let rt = tokio::runtime::Runtime::new().unwrap(); 125 | 126 | let (tx, rx) = flume::unbounded(); 127 | 128 | rt.block_on(async move { 129 | tokio::spawn(async move { 130 | tx.send_async(5).await.unwrap(); 131 | }); 132 | 133 | println!("flume async rx: {}", rx.recv_async().await.unwrap()); 134 | }); 135 | } 136 | 137 | pub fn async_channel_example() { 138 | let rt = tokio::runtime::Runtime::new().unwrap(); 139 | 140 | let (tx, rx) = async_channel::unbounded(); 141 | 142 | rt.block_on(async move { 143 | tokio::spawn(async move { 144 | tx.send(5).await.unwrap(); 145 | }); 146 | 147 | println!("rx: {}", rx.recv().await.unwrap()); 148 | }); 149 | } 150 | 151 | pub fn futures_channel_mpsc_example() { 152 | let rt = tokio::runtime::Runtime::new().unwrap(); 153 | 154 | let (tx, mut rx) = futures_channel::mpsc::channel(3); 155 | 156 | rt.block_on(async move { 157 | tokio::spawn(async move { 158 | for _ in 0..3 { 159 | let mut tx = tx.clone(); 160 | thread::spawn(move || tx.start_send("ok")); 161 | } 162 | 163 | drop(tx); 164 | }); 165 | 166 | // Unbounded receiver waiting for all senders to complete. 167 | while let Ok(msg) = rx.try_next() { 168 | println!("{:?}", msg); 169 | } 170 | 171 | println!("futures_channel_mpsc_example completed"); 172 | }); 173 | } 174 | 175 | pub fn futures_channel_oneshot_example() { 176 | use futures::channel::oneshot; 177 | use std::time::Duration; 178 | 179 | let (sender, receiver) = oneshot::channel::(); 180 | 181 | thread::spawn(|| { 182 | println!("THREAD: sleeping zzz..."); 183 | thread::sleep(Duration::from_millis(1000)); 184 | println!("THREAD: i'm awake! sending."); 185 | sender.send(3).unwrap(); 186 | }); 187 | 188 | println!("MAIN: doing some useful stuff"); 189 | 190 | futures::executor::block_on(async { 191 | println!("MAIN: waiting for msg..."); 192 | println!("MAIN: got: {:?}", receiver.await) 193 | }); 194 | } 195 | 196 | pub fn async_priority_channel_example() { 197 | let rt = tokio::runtime::Runtime::new().unwrap(); 198 | 199 | let (s, r) = async_priority_channel::unbounded(); 200 | 201 | rt.block_on(async move { 202 | tokio::spawn(async move { 203 | assert_eq!(s.send("Foo", 0).await, Ok(())); 204 | assert_eq!(s.send("Bar", 2).await, Ok(())); 205 | assert_eq!(s.send("Baz", 1).await, Ok(())); 206 | }); 207 | 208 | assert_eq!(r.recv().await, Ok(("Bar", 2))); 209 | }); 210 | } 211 | 212 | pub fn kanal_example() { 213 | let (tx, rx) = kanal::unbounded(); 214 | 215 | thread::spawn(move || { 216 | (0..10).for_each(|i| { 217 | tx.send(i).unwrap(); 218 | }); 219 | 220 | drop(tx) 221 | }); 222 | 223 | let received: u32 = rx.sum(); 224 | 225 | println!("received sum: {}", received); 226 | } 227 | 228 | pub fn kanal_async_example() { 229 | let rt = tokio::runtime::Runtime::new().unwrap(); 230 | 231 | let (tx, rx) = kanal::unbounded_async(); 232 | 233 | rt.block_on(async move { 234 | tokio::spawn(async move { 235 | tx.send(5).await.unwrap(); 236 | }); 237 | 238 | println!("rx: {}", rx.recv().await.unwrap()); 239 | }); 240 | } 241 | 242 | pub fn kanal_oneshot_example() { 243 | let (tx, rx) = kanal::oneshot(); 244 | 245 | thread::spawn(move || { 246 | tx.send(5).unwrap(); 247 | }); 248 | 249 | println!("kanal oneshot rx: {}", rx.recv().unwrap()); 250 | } -------------------------------------------------------------------------------- /collections/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "collections" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | cuckoofilter = "0.5.0" 10 | dashmap = "5.5.3" 11 | evmap = "10.0.2" 12 | -------------------------------------------------------------------------------- /collections/src/lib.rs: -------------------------------------------------------------------------------- 1 | use cuckoofilter::CuckooFilter; 2 | use dashmap::DashMap; 3 | use std::collections::LinkedList; 4 | use std::{ 5 | collections::HashMap, 6 | sync::{Arc, Mutex}, 7 | }; 8 | 9 | pub fn common_thread_safe_collections() { 10 | let map: HashMap = HashMap::new(); 11 | let m = Arc::new(Mutex::new(map)); 12 | 13 | let mut handles = vec![]; 14 | for i in 0..10 { 15 | let m = Arc::clone(&m); 16 | handles.push(std::thread::spawn(move || { 17 | let mut map = m.lock().unwrap(); 18 | map.insert(i, i); 19 | })); 20 | } 21 | 22 | for handle in handles { 23 | handle.join().unwrap(); 24 | } 25 | 26 | println!("HashMap: {:?}", *m.lock().unwrap()); 27 | } 28 | 29 | pub fn common_thread_safe_vec() { 30 | let vec1 = vec![]; 31 | let vec2 = Arc::new(Mutex::new(vec1)); 32 | 33 | let mut handles = vec![]; 34 | for i in 0..10 { 35 | let vec3 = Arc::clone(&vec2); 36 | handles.push(std::thread::spawn(move || { 37 | let mut v = vec3.lock().unwrap(); 38 | v.push(i); 39 | })); 40 | } 41 | 42 | for handle in handles { 43 | handle.join().unwrap(); 44 | } 45 | 46 | println!("vec: {:?}", vec2.lock().unwrap()); 47 | } 48 | 49 | pub fn common_thread_safe_linkedlist() { 50 | let list1: LinkedList = LinkedList::new(); 51 | let list2 = Arc::new(Mutex::new(list1)); 52 | 53 | let mut handles = vec![]; 54 | for i in 0..10 { 55 | let list3 = Arc::clone(&list2); 56 | handles.push(std::thread::spawn(move || { 57 | let mut v = list3.lock().unwrap(); 58 | v.push_back(i); 59 | })); 60 | } 61 | 62 | for handle in handles { 63 | handle.join().unwrap(); 64 | } 65 | 66 | println!("LinkedList: {:?}", list2.lock().unwrap()); 67 | } 68 | 69 | pub fn dashmap_example() { 70 | let map = Arc::new(DashMap::new()); 71 | let mut handles = vec![]; 72 | 73 | for i in 0..10 { 74 | let map = Arc::clone(&map); 75 | handles.push(std::thread::spawn(move || { 76 | map.insert(i, i); 77 | })); 78 | } 79 | 80 | for handle in handles { 81 | handle.join().unwrap(); 82 | } 83 | 84 | println!("DashMap: {:?}", map); 85 | } 86 | 87 | pub fn cuckoofilter_example() { 88 | let value: &str = "hello world"; 89 | 90 | // Create cuckoo filter with default max capacity of 1000000 items 91 | let mut cf = CuckooFilter::new(); 92 | 93 | // Add data to the filter 94 | cf.add(value).unwrap(); 95 | 96 | // Lookup if data is in the filter 97 | let success = cf.contains(value); 98 | assert!(success); 99 | 100 | // Test and add to the filter (if data does not exists then add) 101 | let success = cf.test_and_add(value).unwrap(); 102 | assert!(!success); 103 | 104 | // Remove data from the filter. 105 | let success = cf.delete(value); 106 | assert!(success); 107 | } 108 | 109 | pub fn evmap_example() { 110 | let (book_reviews_r, book_reviews_w) = evmap::new(); 111 | 112 | // start some writers. 113 | // since evmap does not support concurrent writes, we need 114 | // to protect the write handle by a mutex. 115 | let w = Arc::new(Mutex::new(book_reviews_w)); 116 | let writers: Vec<_> = (0..4) 117 | .map(|i| { 118 | let w = w.clone(); 119 | std::thread::spawn(move || { 120 | let mut w = w.lock().unwrap(); 121 | w.insert(i, true); 122 | w.refresh(); 123 | }) 124 | }) 125 | .collect(); 126 | 127 | // eventually we should see all the writes 128 | while book_reviews_r.len() < 4 { 129 | std::thread::yield_now(); 130 | } 131 | 132 | // all the threads should eventually finish writing 133 | for w in writers.into_iter() { 134 | assert!(w.join().is_ok()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /collections/src/main.rs: -------------------------------------------------------------------------------- 1 | use collections::*; 2 | 3 | fn main() { 4 | common_thread_safe_collections(); 5 | common_thread_safe_vec(); 6 | common_thread_safe_linkedlist(); 7 | 8 | dashmap_example(); 9 | cuckoofilter_example(); 10 | evmap_example(); 11 | } 12 | -------------------------------------------------------------------------------- /container_primitive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "container_primitive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | beef = "0.5.2" 10 | once_cell = "1.18.0" 11 | -------------------------------------------------------------------------------- /container_primitive/src/box.rs: -------------------------------------------------------------------------------- 1 | use std::boxed::ThinBox; 2 | // Box, casually referred to as a ‘box’, provides the simplest form of heap allocation in Rust. 3 | // Boxes provide ownership for this allocation, and drop their contents when they go out of scope. 4 | // Boxes also ensure that they never allocate more than isize::MAX bytes. 5 | pub fn box_example() { 6 | let b = Box::new(5); 7 | println!("b = {}", b); 8 | } 9 | 10 | pub fn box_example2() { 11 | #[derive(Debug)] 12 | enum List { 13 | Cons(T, Box>), 14 | Nil, 15 | } 16 | 17 | let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); 18 | println!("{list:?}"); 19 | } 20 | 21 | pub fn thin_box_example() { 22 | use std::mem::{size_of, size_of_val}; 23 | let size_of_ptr = size_of::<*const ()>(); 24 | 25 | let box_five = Box::new(5); 26 | let box_slice = Box::<[i32]>::new_zeroed_slice(5); 27 | assert_eq!(size_of_ptr, size_of_val(&box_five)); 28 | assert_eq!(size_of_ptr * 2, size_of_val(&box_slice)); 29 | 30 | 31 | let five = ThinBox::new(5); 32 | let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]); 33 | assert_eq!(size_of_ptr, size_of_val(&five)); 34 | assert_eq!(size_of_ptr, size_of_val(&thin_slice)); 35 | } -------------------------------------------------------------------------------- /container_primitive/src/cell.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::cell::*; 4 | use std::collections::HashMap; 5 | use std::sync::LazyLock; 6 | 7 | // Shareable mutable containers. 8 | // Shareable mutable containers exist to permit mutability in a controlled manner, even in the presence of aliasing. 9 | // Both Cell and RefCell allow doing this in a single-threaded way. However, neither Cell nor RefCell are thread safe (they do not implement Sync). 10 | // If you need to do aliasing and mutation between multiple threads it is possible to use Mutex, RwLock or atomic types. 11 | // 12 | // Cell implements interior mutability by moving values in and out of the Cell. 13 | // To use references instead of values, one must use the RefCell type, acquiring a write lock before mutating. 14 | 15 | pub fn cell_example() { 16 | struct SomeStruct { 17 | regular_field: u8, 18 | special_field: Cell, 19 | } 20 | 21 | // not mutable 22 | let my_struct = SomeStruct { 23 | regular_field: 0, 24 | special_field: Cell::new(1), 25 | }; 26 | 27 | let _ = my_struct.regular_field; 28 | // my_struct.regular_field = 100; 29 | my_struct.special_field.set(100); 30 | 31 | my_struct.special_field.update(|v| v + 1); 32 | } 33 | 34 | pub fn refcell_example() { 35 | #[allow(dead_code)] 36 | struct SomeStruct { 37 | regular_field: u8, 38 | special_field: RefCell, 39 | } 40 | 41 | // not mutable 42 | let my_struct = SomeStruct { 43 | regular_field: 0, 44 | special_field: RefCell::new(1), 45 | }; 46 | 47 | // my_struct.regular_field = 100; 48 | let mut special_field = (&my_struct.special_field).borrow_mut(); 49 | *special_field = 100; 50 | drop(special_field); 51 | 52 | println!("special_field = {}", my_struct.special_field.borrow()); 53 | 54 | (&my_struct).special_field.replace(200); 55 | println!("special_field = {}", my_struct.special_field.borrow()); 56 | } 57 | 58 | 59 | 60 | pub fn once_cell_example() { 61 | let cell = OnceCell::new(); 62 | assert!(cell.get().is_none()); 63 | 64 | let value: &String = cell.get_or_init(|| "Hello, World!".to_string()); 65 | assert_eq!(value, "Hello, World!"); 66 | assert!(cell.get().is_some()); 67 | } 68 | 69 | pub fn lazy_cell_example() { 70 | let lazy: LazyCell = LazyCell::new(|| { 71 | println!("initializing"); 72 | 92 73 | }); 74 | println!("one_cell ready"); 75 | println!("{}", *lazy); 76 | println!("{}", *lazy); 77 | } 78 | 79 | static HASHMAP: LazyLock> = LazyLock::new(|| { 80 | println!("initializing"); 81 | let mut m = HashMap::new(); 82 | m.insert(13, "Spica".to_string()); 83 | m.insert(74, "Hoyten".to_string()); 84 | m 85 | }); 86 | 87 | pub fn lazy_lock() { 88 | println!("ready"); 89 | std::thread::spawn(|| { 90 | println!("{:?}", HASHMAP.get(&13)); 91 | }).join().unwrap(); 92 | println!("{:?}", HASHMAP.get(&74)); 93 | } -------------------------------------------------------------------------------- /container_primitive/src/cow.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::mem::size_of; 3 | 4 | // The type Cow is a smart pointer providing clone-on-write functionality: 5 | // it can enclose and provide immutable access to borrowed data, 6 | // and clone the data lazily when mutation or ownership is required. 7 | pub fn cow_example() { 8 | let origin = "hello world"; 9 | let mut cow = Cow::from(origin); // Cow::Borrowed 10 | assert_eq!(cow, "hello world"); 11 | 12 | // Cow can be borrowed as a str 13 | let s: &str = &cow; 14 | assert_eq!(s, "hello world"); 15 | 16 | assert_eq!(s.len(), cow.len()); 17 | 18 | // Cow can be borrowed as a mut str 19 | let s: &mut str = cow.to_mut(); 20 | s.make_ascii_uppercase(); 21 | assert_eq!(s, "HELLO WORLD"); 22 | assert_eq!(origin, "hello world"); 23 | 24 | // Cow can be cloned 25 | let cow2 = cow.clone(); 26 | assert_eq!(cow2, "HELLO WORLD"); 27 | assert_eq!(origin, "hello world"); 28 | 29 | // Cow can be converted to a String 30 | let s: String = cow.into(); 31 | assert_eq!(s, "HELLO WORLD"); 32 | } 33 | 34 | pub fn cow_example2() { 35 | fn abs_all(input: &mut Cow<[i32]>) { 36 | for i in 0..input.len() { 37 | let v = input[i]; 38 | if v < 0 { 39 | // Clones into a vector if not already owned. 40 | input.to_mut()[i] = -v; 41 | } 42 | } 43 | } 44 | 45 | // No clone occurs because `input` doesn't need to be mutated. 46 | let slice = [0, 1, 2]; 47 | let mut input = Cow::from(&slice[..]); 48 | abs_all(&mut input); 49 | println!("origin: {:?}, mutated: {:?}", &slice, &input); 50 | 51 | // Clone occurs because `input` needs to be mutated. 52 | let slice = [-1, 0, 1]; 53 | let mut input = Cow::from(&slice[..]); 54 | abs_all(&mut input); 55 | println!("origin: {:?}, mutated: {:?}", &slice, &input); 56 | 57 | // No clone occurs because `input` is already owned. 58 | let mut input = Cow::from(vec![-1, 0, 1]); 59 | abs_all(&mut input); 60 | 61 | } 62 | 63 | pub fn beef_cow() { 64 | let borrowed: beef::Cow = beef::Cow::borrowed("Hello"); 65 | let owned: beef::Cow = beef::Cow::owned(String::from("World")); 66 | let _ = beef::Cow::from("Hello"); 67 | 68 | assert_eq!(format!("{} {}!", borrowed, owned), "Hello World!",); 69 | 70 | const WORD: usize = size_of::(); 71 | 72 | assert_eq!(size_of::>(), 3 * WORD); 73 | assert_eq!(size_of::>(), 3 * WORD); 74 | assert_eq!(size_of::>(), 2 * WORD); 75 | } 76 | -------------------------------------------------------------------------------- /container_primitive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(lazy_cell)] 2 | #![feature(thin_box)] 3 | #![feature(new_uninit)] 4 | #![feature(cell_update)] 5 | 6 | pub mod cow; 7 | pub mod r#box; 8 | pub mod cell; 9 | pub mod rc; 10 | 11 | pub use cow::*; 12 | pub use r#box::*; 13 | pub use cell::*; 14 | pub use rc::*; -------------------------------------------------------------------------------- /container_primitive/src/main.rs: -------------------------------------------------------------------------------- 1 | use container_primitive::*; 2 | 3 | fn main() { 4 | cow_example(); 5 | cow_example2(); 6 | beef_cow(); 7 | 8 | box_example(); 9 | box_example2(); 10 | thin_box_example(); 11 | 12 | cell_example(); 13 | refcell_example(); 14 | rc_refcell_example(); 15 | once_cell_example(); 16 | lazy_cell_example(); 17 | lazy_lock(); 18 | 19 | rc_example(); 20 | myrc_example(); 21 | } -------------------------------------------------------------------------------- /container_primitive/src/rc.rs: -------------------------------------------------------------------------------- 1 | 2 | // Single-threaded reference-counting pointers. ‘Rc’ stands for ‘Reference Counted’. 3 | 4 | use std::collections::HashMap; 5 | use std::rc::Rc; 6 | use std::cell::{RefCell,RefMut}; 7 | 8 | pub fn rc_example() { 9 | let rc = Rc::new(1); 10 | 11 | let rc2 = rc.clone(); 12 | let rc3 = Rc::clone(&rc); 13 | println!("rc2: {}, rc3:{}", rc2, rc3); 14 | 15 | let my_weak = Rc::downgrade(&rc); 16 | drop(rc); 17 | drop(rc2); 18 | drop(rc3); 19 | 20 | println!("my_weak: {}", my_weak.upgrade().is_none()); 21 | 22 | } 23 | 24 | pub fn rc_refcell_example() { 25 | let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new())); 26 | // Create a new block to limit the scope of the dynamic borrow 27 | { 28 | let mut map: RefMut<_> = shared_map.borrow_mut(); 29 | map.insert("africa", 92388); 30 | map.insert("kyoto", 11837); 31 | map.insert("piccadilly", 11826); 32 | map.insert("marbles", 38); 33 | } 34 | 35 | // Note that if we had not let the previous borrow of the cache fall out 36 | // of scope then the subsequent borrow would cause a dynamic thread panic. 37 | // This is the major hazard of using `RefCell`. 38 | let total: i32 = shared_map.borrow().values().sum(); 39 | println!("{total}"); 40 | } 41 | 42 | pub fn myrc_example() { 43 | let s = example::Rc::new("hello world"); 44 | let s1 = s.clone(); 45 | 46 | let v = s1.value(); 47 | println!("myrc value: {}", v); 48 | } 49 | 50 | pub mod example { 51 | use std::cell::Cell; 52 | use std::marker::PhantomData; 53 | use std::process::abort; 54 | use std::ptr::NonNull; 55 | 56 | pub struct Rc { 57 | ptr: NonNull>, 58 | phantom: PhantomData>, 59 | } 60 | 61 | impl Rc { 62 | pub fn new(t: T) -> Self { 63 | let ptr = Box::new(RcBox { 64 | strong: Cell::new(1), 65 | refcount: Cell::new(1), 66 | value: t, 67 | }); 68 | let ptr = NonNull::new(Box::into_raw(ptr)).unwrap(); 69 | Self { 70 | ptr: ptr, 71 | phantom: PhantomData, 72 | } 73 | } 74 | 75 | pub fn value(&self) -> &T { 76 | &self.inner().value 77 | } 78 | } 79 | 80 | 81 | struct RcBox { 82 | strong: Cell, 83 | refcount: Cell, 84 | value: T, 85 | } 86 | 87 | impl Clone for Rc { 88 | fn clone(&self) -> Rc { 89 | self.inc_strong(); 90 | Rc { 91 | ptr: self.ptr, 92 | phantom: PhantomData, 93 | } 94 | } 95 | } 96 | 97 | trait RcBoxPtr { 98 | fn inner(&self) -> &RcBox; 99 | 100 | fn strong(&self) -> usize { 101 | self.inner().strong.get() 102 | } 103 | 104 | fn inc_strong(&self) { 105 | self.inner() 106 | .strong 107 | .set(self.strong().checked_add(1).unwrap_or_else(|| abort())); 108 | } 109 | } 110 | 111 | impl RcBoxPtr for Rc { 112 | fn inner(&self) -> &RcBox { 113 | unsafe { self.ptr.as_ref() } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /crossbeam_examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crossbeam_examples" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | crossbeam = "0.8.2" 10 | -------------------------------------------------------------------------------- /crossbeam_examples/src/atomics.rs: -------------------------------------------------------------------------------- 1 | use crossbeam::atomic::AtomicCell; 2 | 3 | pub fn atomic_cell_example() { 4 | let a = AtomicCell::new(0i32); 5 | 6 | a.store(1); 7 | assert_eq!(a.load(), 1); 8 | 9 | assert_eq!(a.compare_exchange(1, 2), Ok(1)); 10 | assert_eq!(a.fetch_add(1), 2); 11 | assert_eq!(a.load(), 3); 12 | assert_eq!(a.swap(100), 3); 13 | assert_eq!(a.load(), 100); 14 | assert_eq!(a.into_inner(), 100); 15 | 16 | let a = AtomicCell::new(100i32); 17 | let v = a.take(); 18 | assert_eq!(v, 100); 19 | assert_eq!(a.load(), 0); 20 | } 21 | -------------------------------------------------------------------------------- /crossbeam_examples/src/collections.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::Mutex; 3 | use std::thread; 4 | use std::iter; 5 | 6 | use crossbeam::deque::{Injector, Steal, Stealer, Worker}; 7 | use crossbeam::queue::{ArrayQueue,SegQueue}; 8 | 9 | pub fn crossbeam_deque_example() { 10 | let worker = Worker::new_fifo(); 11 | let stealer = worker.stealer(); 12 | 13 | // test worker and stealer 14 | let worker_handle = thread::spawn(move || { 15 | worker.push(1); 16 | worker.push(2); 17 | worker.push(3); 18 | worker.push(4); 19 | worker.push(5); 20 | }); 21 | 22 | let stealer_handle = thread::spawn(move || { 23 | assert_eq!(stealer.steal(), Steal::Success(1)); 24 | assert_eq!(stealer.steal(), Steal::Success(2)); 25 | assert_eq!(stealer.steal(), Steal::Success(3)); 26 | assert_eq!(stealer.steal(), Steal::Success(4)); 27 | assert_eq!(stealer.steal(), Steal::Success(5)); 28 | assert_eq!(stealer.steal(), Steal::Empty); 29 | }); 30 | 31 | worker_handle.join().unwrap(); 32 | stealer_handle.join().unwrap(); 33 | 34 | // test global queue (injector) and worker 35 | let worker = Worker::new_fifo(); 36 | let injector = Arc::new(Mutex::new(Injector::new())); 37 | 38 | // test worker and stealer 39 | let injector1 = injector.clone(); 40 | let injector_handle = thread::spawn(move || { 41 | let injector = injector1.lock().unwrap(); 42 | injector.push(1); 43 | injector.push(2); 44 | injector.push(3); 45 | injector.push(4); 46 | injector.push(5); 47 | }); 48 | injector_handle.join().unwrap(); 49 | 50 | let injector2 = injector.clone(); 51 | let global_handle = thread::spawn(move || { 52 | let injector = injector2.lock().unwrap(); 53 | 54 | // steal the half of the data 55 | let _ = injector.steal_batch(&worker); 56 | assert_eq!(worker.pop(), Some(1)); 57 | assert_eq!(worker.pop(), Some(2)); 58 | assert_eq!(worker.pop(), Some(3)); 59 | 60 | let _ = injector.steal_batch(&worker); 61 | assert_eq!(worker.pop(), Some(4)); 62 | let _ = injector.steal_batch(&worker); 63 | assert_eq!(worker.pop(), Some(5)); 64 | let _ = injector.steal_batch(&worker); 65 | assert_eq!(worker.pop(), None); 66 | }); 67 | 68 | global_handle.join().unwrap(); 69 | 70 | 71 | // find_task 72 | let worker1 = Worker::new_fifo(); 73 | let stealer1 = worker1.stealer(); 74 | let worker2 = Worker::new_fifo(); 75 | let stealer2 = worker2.stealer(); 76 | let stealers = vec![stealer1,stealer2]; 77 | let injector = Arc::new(Mutex::new(Injector::new())); 78 | 79 | let worker_handle = thread::spawn(move || { 80 | worker1.push(1); 81 | worker1.push(2); 82 | worker1.push(3); 83 | worker1.push(4); 84 | worker1.push(5); 85 | 86 | assert_eq!(worker1.pop(), Some(1)); 87 | }); 88 | worker_handle.join().unwrap(); 89 | 90 | 91 | let injector1 = injector.clone(); 92 | let worker2_handle = thread::spawn(move || { 93 | assert_eq!(find_task(&worker2, injector.clone(), &stealers[..]), Some(2)); 94 | assert_eq!(find_task(&worker2, injector1.clone(), &stealers[..]), Some(3)); 95 | assert_eq!(find_task(&worker2, injector1.clone(), &stealers[..]), Some(4)); 96 | assert_eq!(find_task(&worker2, injector1.clone(), &stealers[..]), Some(5)); 97 | }); 98 | 99 | worker2_handle.join().unwrap(); 100 | 101 | 102 | } 103 | 104 | fn find_task(local: &Worker, global: Arc>>, stealers: &[Stealer]) -> Option { 105 | 106 | // Pop a task from the local queue, if not empty. 107 | local.pop().or_else(|| { 108 | // Otherwise, we need to look for a task elsewhere. 109 | iter::repeat_with(|| { 110 | // Try stealing a batch of tasks from the global queue. 111 | let global = global.lock().unwrap(); 112 | global 113 | .steal_batch_and_pop(local) 114 | // Or try stealing a task from one of the other threads. 115 | .or_else(|| stealers.iter().map(|s| s.steal()).collect()) 116 | }) 117 | // Loop while no task was stolen and any steal operation needs to be retried. 118 | .find(|s| !s.is_retry()) 119 | // Extract the stolen task, if there is one. 120 | .and_then(|s| s.success()) 121 | }) 122 | } 123 | 124 | pub fn arrayqueue_example() { 125 | let q = Arc::new(ArrayQueue::new(2)); 126 | 127 | let q1 = q.clone(); 128 | let p = thread::spawn(move || { 129 | q1.push(1).unwrap(); 130 | q1.push(2).unwrap(); 131 | }); 132 | 133 | let q2 = q.clone(); 134 | let c = thread::spawn(move || { 135 | println!("q2 pop: {}", q2.pop().unwrap_or(-1)); 136 | println!("q2 pop: {}", q2.pop().unwrap_or(-1)); 137 | }); 138 | 139 | p.join().unwrap(); 140 | c.join().unwrap(); 141 | } 142 | 143 | 144 | pub fn segqueue_example() { 145 | let q = Arc::new(SegQueue::new()); 146 | 147 | let q1 = q.clone(); 148 | let p = thread::spawn(move || { 149 | q1.push(1); 150 | q1.push(2); 151 | }); 152 | 153 | let q2 = q.clone(); 154 | let c = thread::spawn(move || { 155 | println!("SegQueue q2 pop: {}", q2.pop().unwrap_or(-1)); 156 | println!("SegQueue q2 pop: {}", q2.pop().unwrap_or(-1)); 157 | }); 158 | 159 | p.join().unwrap(); 160 | c.join().unwrap(); 161 | } -------------------------------------------------------------------------------- /crossbeam_examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod atomics; 2 | pub mod collections; 3 | pub mod primitives; 4 | pub mod util; 5 | 6 | pub use atomics::*; 7 | pub use collections::*; 8 | pub use primitives::*; 9 | pub use util::*; -------------------------------------------------------------------------------- /crossbeam_examples/src/main.rs: -------------------------------------------------------------------------------- 1 | use crossbeam_examples::*; 2 | 3 | fn main() { 4 | atomic_cell_example(); 5 | atomic_consume_example(); 6 | 7 | crossbeam_deque_example(); 8 | arrayqueue_example(); 9 | segqueue_example(); 10 | 11 | unbounded_channel_example(); 12 | bounded_channel_example(); 13 | channel_iter_example(); 14 | channel_select_example(); 15 | channel_extra_example(); 16 | sharded_lock_example(); 17 | waitgroup_example(); 18 | parker_example(); 19 | 20 | backoff_example(); 21 | cachepadded_example(); 22 | scope_example(); 23 | } 24 | -------------------------------------------------------------------------------- /crossbeam_examples/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use crossbeam::thread; 2 | use std::sync::Arc; 3 | use std::time::*; 4 | 5 | use crossbeam::channel::*; 6 | use crossbeam::sync::Parker; 7 | use crossbeam::sync::ShardedLock; 8 | use crossbeam::sync::WaitGroup; 9 | 10 | pub fn unbounded_channel_example() { 11 | let (sender, receiver) = unbounded(); 12 | 13 | let sender1 = sender.clone(); 14 | 15 | thread::scope(|s| { 16 | s.spawn(|_| { 17 | sender.send(1).unwrap(); 18 | sender.send(2).unwrap(); 19 | sender1.send(3).unwrap(); 20 | }); 21 | 22 | assert_eq!(receiver.recv(), Ok(1)); 23 | assert_eq!(receiver.recv(), Ok(2)); 24 | assert_eq!(receiver.recv(), Ok(3)); 25 | }) 26 | .unwrap(); 27 | } 28 | 29 | pub fn bounded_channel_example() { 30 | let (sender, receiver) = bounded(2); 31 | 32 | thread::scope(|s| { 33 | s.spawn(|_| { 34 | sender.send(1).unwrap(); 35 | sender.send(2).unwrap(); 36 | sender.send(3).unwrap(); 37 | }); 38 | 39 | assert_eq!(receiver.recv(), Ok(1)); 40 | assert_eq!(receiver.recv(), Ok(2)); 41 | assert_eq!(receiver.recv(), Ok(3)); 42 | }) 43 | .unwrap(); 44 | } 45 | 46 | pub fn channel_iter_example() { 47 | let (sender, receiver) = unbounded(); 48 | 49 | thread::scope(|s| { 50 | s.spawn(|_| { 51 | sender.send(1).unwrap(); 52 | sender.send(2).unwrap(); 53 | sender.send(3).unwrap(); 54 | drop(sender); // Disconnect the channel. 55 | }); 56 | 57 | let v: Vec = receiver.iter().collect(); 58 | println!("channel_iter_example: {:?}", v); 59 | }) 60 | .unwrap(); 61 | } 62 | 63 | pub fn channel_select_example() { 64 | let (s1, r1) = unbounded(); 65 | let (s2, r2) = unbounded(); 66 | 67 | std::thread::spawn(move || s1.send(10).unwrap()); 68 | std::thread::spawn(move || s2.send(20).unwrap()); 69 | 70 | // At most one of these two receive operations will be executed. 71 | select! { 72 | recv(r1) -> msg => println!("r1 received {}", msg.unwrap()), 73 | recv(r2) -> msg => println!("r2 received {}", msg.unwrap()), 74 | default(Duration::from_secs(1)) => println!("timed out"), 75 | } 76 | } 77 | 78 | pub fn channel_extra_example() { 79 | let (s1, r1) = unbounded(); 80 | std::thread::spawn(move || { 81 | std::thread::sleep(Duration::from_secs(2)); 82 | s1.send(10).unwrap() 83 | }); 84 | 85 | let start = Instant::now(); 86 | let ticker = tick(Duration::from_millis(50)); 87 | let timeout = after(Duration::from_secs(1)); 88 | 89 | loop { 90 | select! { 91 | recv(r1) -> msg => {println!("r1 received {}", msg.unwrap());break}, 92 | recv(ticker) -> _ => println!("elapsed: {:?}", start.elapsed()), 93 | recv(timeout) -> _ => {println!("elapsed: {:?}, timeout", start.elapsed());break}, 94 | } 95 | } 96 | } 97 | 98 | pub fn sharded_lock_example() { 99 | let lock = Arc::new(ShardedLock::new(0)); 100 | 101 | let handles: Vec<_> = (0..10) 102 | .map(|i| { 103 | let lock = lock.clone(); 104 | std::thread::spawn(move || { 105 | if i % 2 == 0 { 106 | let mut num = lock.write().unwrap(); 107 | *num += 1; 108 | } else { 109 | let num = lock.read().unwrap(); 110 | println!("thread {} read {}", i, num); 111 | } 112 | }) 113 | }) 114 | .collect(); 115 | 116 | for handle in handles { 117 | handle.join().unwrap(); 118 | } 119 | } 120 | 121 | pub fn waitgroup_example() { 122 | let wg = WaitGroup::new(); 123 | 124 | for i in 0..4 { 125 | let wg = wg.clone(); 126 | std::thread::spawn(move || { 127 | println!("waitgroup_example thread: {}", i); 128 | drop(wg); // wg.wait(); 129 | }); 130 | } 131 | wg.wait(); 132 | 133 | println!("waitgroup_example: done"); 134 | } 135 | 136 | pub fn parker_example() { 137 | let p = Parker::new(); 138 | let u = p.unparker().clone(); 139 | 140 | // Make the token available. 141 | u.unpark(); 142 | // Wakes up immediately and consumes the token. 143 | p.park(); 144 | 145 | std::thread::spawn(move || { 146 | std::thread::sleep(Duration::from_millis(500)); 147 | u.unpark(); 148 | }); 149 | 150 | // Wakes up when `u.unpark()` provides the token. 151 | println!("parking..."); 152 | p.park(); 153 | println!("unparked"); 154 | } 155 | -------------------------------------------------------------------------------- /crossbeam_examples/src/util.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::AtomicBool; 2 | use std::sync::atomic::Ordering::SeqCst; 3 | use std::sync::Arc; 4 | use std::thread; 5 | use std::time::Duration; 6 | 7 | use crossbeam::utils::Backoff; 8 | use crossbeam::utils::CachePadded; 9 | 10 | pub fn backoff_example() { 11 | fn spin_wait(ready: &AtomicBool) { 12 | let backoff = Backoff::new(); 13 | while !ready.load(SeqCst) { 14 | backoff.snooze(); 15 | } 16 | } 17 | 18 | let ready = Arc::new(AtomicBool::new(false)); 19 | let ready2 = ready.clone(); 20 | 21 | thread::spawn(move || { 22 | thread::sleep(Duration::from_millis(100)); 23 | ready2.store(true, SeqCst); 24 | }); 25 | 26 | assert_eq!(ready.load(SeqCst), false); 27 | spin_wait(&ready); 28 | assert_eq!(ready.load(SeqCst), true); 29 | } 30 | 31 | pub fn cachepadded_example() { 32 | let array = [CachePadded::new(1i8), CachePadded::new(2i8)]; 33 | let addr1 = &*array[0] as *const i8 as usize; 34 | let addr2 = &*array[1] as *const i8 as usize; 35 | 36 | assert!(addr2 - addr1 >= 128); 37 | assert_eq!(addr1 % 128, 0); 38 | assert_eq!(addr2 % 128, 0); 39 | } 40 | 41 | pub fn scope_example() { 42 | let v = vec![1, 2, 3]; 43 | 44 | crossbeam::thread::scope(|s| { 45 | s.spawn(|_| { 46 | println!("A child thread borrowing `v`: {:?}", v); 47 | }); 48 | }) 49 | .unwrap(); 50 | 51 | println!("scope_exampleg `v`: {:?}", v); 52 | } 53 | -------------------------------------------------------------------------------- /parking_lot_examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parking_lot_examples" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | parking_lot = "0.12.1" 10 | -------------------------------------------------------------------------------- /parking_lot_examples/src/customized_lock.rs: -------------------------------------------------------------------------------- 1 | use lock_api::{RawMutex, Mutex, GuardSend}; 2 | use std::sync::atomic::{AtomicBool, Ordering}; 3 | 4 | // 1. Define our raw lock type 5 | pub struct RawSpinlock(AtomicBool); 6 | 7 | // 2. Implement RawMutex for this type 8 | unsafe impl RawMutex for RawSpinlock { 9 | const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false)); 10 | 11 | // A spinlock guard can be sent to another thread and unlocked there 12 | type GuardMarker = GuardSend; 13 | 14 | fn lock(&self) { 15 | // Note: This isn't the best way of implementing a spinlock, but it 16 | // suffices for the sake of this example. 17 | while !self.try_lock() {} 18 | } 19 | 20 | fn try_lock(&self) -> bool { 21 | self.0 22 | .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) 23 | .is_ok() 24 | } 25 | 26 | unsafe fn unlock(&self) { 27 | self.0.store(false, Ordering::Release); 28 | } 29 | } 30 | 31 | // 3. Export the wrappers. This are the types that your users will actually use. 32 | pub type Spinlock = lock_api::Mutex; 33 | pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>; -------------------------------------------------------------------------------- /parking_lot_examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{mpsc::channel, Arc}; 2 | use std::thread; 3 | 4 | use parking_lot::RwLock; 5 | use parking_lot::{FairMutex, Mutex, Once, ReentrantMutex}; 6 | 7 | pub fn mutex_example() { 8 | const N: usize = 10; 9 | 10 | let data = Arc::new(Mutex::new(0)); 11 | let data2 = &data.clone(); 12 | 13 | let (tx, rx) = channel(); 14 | for _ in 0..10 { 15 | let (data, tx) = (Arc::clone(&data), tx.clone()); 16 | thread::spawn(move || { 17 | // The shared state can only be accessed once the lock is held. 18 | // Our non-atomic increment is safe because we're the only thread 19 | // which can access the shared state when the lock is held. 20 | let mut data = data.lock(); 21 | *data += 1; 22 | if *data == N { 23 | tx.send(()).unwrap(); 24 | } 25 | // the lock is unlocked here when `data` goes out of scope. 26 | }); 27 | } 28 | 29 | rx.recv().unwrap(); 30 | 31 | println!("mutex_example: {}", data2.lock()); 32 | } 33 | 34 | pub fn mutex_example2() { 35 | const N: usize = 10; 36 | 37 | let mutex = Arc::new(Mutex::new(())); 38 | 39 | let handles: Vec<_> = (0..N) 40 | .map(|i| { 41 | let mutex = Arc::clone(&mutex); 42 | thread::spawn(move || { 43 | let _lock = mutex.lock(); 44 | println!("thread {} done", i); 45 | }) 46 | }) 47 | .collect(); 48 | 49 | for handle in handles { 50 | handle.join().unwrap(); 51 | } 52 | 53 | println!("mutex_example2: done"); 54 | } 55 | 56 | pub fn mutex_example3() { 57 | const N: usize = 10; 58 | 59 | let mutex = Arc::new(Mutex::new(())); 60 | 61 | let handles: Vec<_> = (0..N) 62 | .map(|i| { 63 | let mutex = Arc::clone(&mutex); 64 | thread::spawn(move || match mutex.try_lock() { 65 | Some(_guard) => println!("thread {} got the lock", i), 66 | None => println!("thread {} did not get the lock", i), 67 | }) 68 | }) 69 | .collect(); 70 | 71 | for handle in handles { 72 | handle.join().unwrap(); 73 | } 74 | 75 | println!("mutex_example3: done"); 76 | } 77 | 78 | pub fn mutex_example4() { 79 | use parking_lot::Mutex; 80 | use std::mem; 81 | 82 | let mutex = Mutex::new(1); 83 | 84 | // 使用mem::forget持有锁直到结束 85 | let _guard = mem::forget(mutex.lock()); 86 | 87 | // 一些访问受mutex保护的数据的代码 88 | 89 | // 在结束前解锁mutex 90 | unsafe { 91 | mutex.force_unlock(); 92 | } 93 | 94 | println!("mutex_example4: done"); 95 | } 96 | 97 | pub fn fairmutex_example() { 98 | const N: usize = 10; 99 | 100 | let data = Arc::new(FairMutex::new(0)); 101 | 102 | let (tx, rx) = channel(); 103 | for _ in 0..10 { 104 | let (data, tx) = (Arc::clone(&data), tx.clone()); 105 | thread::spawn(move || { 106 | // The shared state can only be accessed once the lock is held. 107 | // Our non-atomic increment is safe because we're the only thread 108 | // which can access the shared state when the lock is held. 109 | let mut data = data.lock(); 110 | *data += 1; 111 | if *data == N { 112 | tx.send(()).unwrap(); 113 | } 114 | // the lock is unlocked here when `data` goes out of scope. 115 | }); 116 | } 117 | 118 | rx.recv().unwrap(); 119 | 120 | println!("fairmutex_example: done"); 121 | } 122 | 123 | pub fn rwmutex_example() { 124 | const N: usize = 10; 125 | 126 | let lock = Arc::new(RwLock::new(5)); 127 | 128 | let handles: Vec<_> = (0..N) 129 | .map(|i| { 130 | let lock = Arc::clone(&lock); 131 | thread::spawn(move || { 132 | if i % 2 == 0 { 133 | let mut num = lock.write(); 134 | *num += 1; 135 | } else { 136 | let num = lock.read(); 137 | println!("thread {} read {}", i, num); 138 | } 139 | }) 140 | }) 141 | .collect(); 142 | 143 | for handle in handles { 144 | handle.join().unwrap(); 145 | } 146 | 147 | println!("rwmutex_example: {}", lock.read()); 148 | } 149 | pub fn reentrantmutex_example() { 150 | let lock = ReentrantMutex::new(()); 151 | 152 | reentrant(&lock, 10); 153 | 154 | println!("reentrantMutex_example: done"); 155 | } 156 | 157 | fn reentrant(lock: &ReentrantMutex<()>, i: usize) { 158 | if i == 0 { 159 | return; 160 | } 161 | 162 | let _lock = lock.lock(); 163 | reentrant(lock, i - 1); 164 | } 165 | 166 | pub fn once_example() { 167 | static mut VAL: usize = 0; 168 | static INIT: Once = Once::new(); 169 | fn get_cached_val() -> usize { 170 | unsafe { 171 | INIT.call_once(|| { 172 | println!("initializing once"); 173 | thread::sleep(std::time::Duration::from_secs(1)); 174 | VAL = 100; 175 | }); 176 | VAL 177 | } 178 | } 179 | 180 | let handle = thread::spawn(|| { 181 | println!("thread 1 get_cached_val: {}", get_cached_val()); 182 | }); 183 | 184 | println!("get_cached_val: {}", get_cached_val()); 185 | 186 | handle.join().unwrap(); 187 | } 188 | 189 | pub fn condvar_example() { 190 | use std::sync::Condvar; 191 | use std::sync::Mutex; 192 | 193 | let pair = Arc::new((Mutex::new(false), Condvar::new())); 194 | let pair2 = Arc::clone(&pair); 195 | 196 | thread::spawn(move || { 197 | let (lock, cvar) = &*pair2; 198 | let mut started = lock.lock().unwrap(); 199 | *started = true; 200 | cvar.notify_one(); 201 | }); 202 | 203 | let (lock, cvar) = &*pair; 204 | let mut started = lock.lock().unwrap(); 205 | while !*started { 206 | started = cvar.wait(started).unwrap(); // block until notified 207 | } 208 | println!("condvar_example: done"); 209 | } 210 | -------------------------------------------------------------------------------- /parking_lot_examples/src/main.rs: -------------------------------------------------------------------------------- 1 | use parking_lot_examples::*; 2 | 3 | fn main() { 4 | mutex_example(); 5 | mutex_example2(); 6 | mutex_example3(); 7 | mutex_example4(); 8 | 9 | fairmutex_example(); 10 | 11 | rwmutex_example(); 12 | 13 | reentrantmutex_example(); 14 | 15 | once_example(); 16 | 17 | condvar_example(); 18 | } 19 | -------------------------------------------------------------------------------- /pool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pool" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | executor-service = "0.2.2" 10 | executors = "0.9.0" 11 | fast-threadpool = "0.3.0" 12 | futures-lite = "1.12.0" 13 | poolite = "0.7.1" 14 | rayon = "1.5.3" 15 | rusty_pool = "0.7.0" 16 | scheduled-thread-pool = "0.2.6" 17 | scoped-tls = "1.0.1" 18 | scoped_threadpool = "0.1.9" 19 | smol = "1.2.5" 20 | threadpool = "1.8.1" 21 | threadpool-executor = "0.3.2" 22 | tokio = { version = "1.32.0", features = ["full"] } 23 | workerpool-rs = "0.2.1" 24 | -------------------------------------------------------------------------------- /pool/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicUsize, AtomicI32, Ordering}; 2 | use std::sync::mpsc::channel; 3 | use std::sync::{Arc, Barrier, Mutex}; 4 | use std::thread; 5 | use std::thread::sleep; 6 | use std::time::Duration; 7 | 8 | use fast_threadpool::ThreadPoolConfig; 9 | use rayon; 10 | use rusty_pool; 11 | use tokio; 12 | 13 | fn fib(n: usize) -> usize { 14 | if n == 0 || n == 1 { 15 | return n; 16 | } 17 | let (a, b) = rayon::join(|| fib(n - 1), || fib(n - 2)); // runs inside of `pool` 18 | return a + b; 19 | } 20 | 21 | pub fn rayon_threadpool() { 22 | let pool = rayon::ThreadPoolBuilder::new() 23 | .num_threads(8) 24 | .build() 25 | .unwrap(); 26 | let n = pool.install(|| fib(20)); 27 | println!("{}", n); 28 | } 29 | 30 | scoped_tls::scoped_thread_local!(static POOL_DATA: Vec); 31 | pub fn rayon_threadpool2() { 32 | let pool_data = vec![1, 2, 3]; 33 | 34 | // We haven't assigned any TLS data yet. 35 | assert!(!POOL_DATA.is_set()); 36 | 37 | rayon::ThreadPoolBuilder::new() 38 | .build_scoped( 39 | // Borrow `pool_data` in TLS for each thread. 40 | |thread| POOL_DATA.set(&pool_data, || thread.run()), 41 | // Do some work that needs the TLS data. 42 | |pool| { 43 | pool.install(|| { 44 | assert!(POOL_DATA.is_set()); 45 | assert_eq!(POOL_DATA.with(|data| data.len()), 3); 46 | }) 47 | }, 48 | ) 49 | .unwrap(); 50 | 51 | // Once we've returned, `pool_data` is no longer borrowed. 52 | drop(pool_data); 53 | } 54 | 55 | pub fn threadpool_example() { 56 | let n_workers = 4; 57 | let n_jobs = 8; 58 | let pool = threadpool::ThreadPool::new(n_workers); 59 | 60 | let (tx, rx) = channel(); 61 | for _ in 0..n_jobs { 62 | let tx = tx.clone(); 63 | pool.execute(move || { 64 | tx.send(1) 65 | .expect("channel will be there waiting for the pool"); 66 | }); 67 | } 68 | 69 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 70 | } 71 | 72 | pub fn threadpool_example2() { 73 | // create at least as many workers as jobs or you will deadlock yourself 74 | let n_workers = 42; 75 | let n_jobs = 23; 76 | let pool = threadpool::ThreadPool::new(n_workers); 77 | let an_atomic = Arc::new(AtomicUsize::new(0)); 78 | 79 | assert!(n_jobs <= n_workers, "too many jobs, will deadlock"); 80 | 81 | // create a barrier that waits for all jobs plus the starter thread 82 | let barrier = Arc::new(Barrier::new(n_jobs + 1)); 83 | for _ in 0..n_jobs { 84 | let barrier = barrier.clone(); 85 | let an_atomic = an_atomic.clone(); 86 | 87 | pool.execute(move || { 88 | // do the heavy work 89 | an_atomic.fetch_add(1, Ordering::Relaxed); 90 | 91 | // then wait for the other threads 92 | barrier.wait(); 93 | }); 94 | } 95 | 96 | // wait for the threads to finish the work 97 | barrier.wait(); 98 | assert_eq!(an_atomic.load(Ordering::SeqCst), /* n_jobs = */ 23); 99 | } 100 | 101 | pub fn rusty_pool_example() { 102 | let pool = rusty_pool::ThreadPool::default(); 103 | 104 | for _ in 1..10 { 105 | pool.execute(|| { 106 | println!("Hello from a rusty_pool!"); 107 | }); 108 | } 109 | 110 | pool.join(); 111 | 112 | let handle = pool.evaluate(|| { 113 | thread::sleep(Duration::from_secs(5)); 114 | return 4; 115 | }); 116 | let result = handle.await_complete(); 117 | assert_eq!(result, 4); 118 | } 119 | 120 | async fn some_async_fn(x: i32, y: i32) -> i32 { 121 | x + y 122 | } 123 | 124 | async fn other_async_fn(x: i32, y: i32) -> i32 { 125 | x - y 126 | } 127 | 128 | pub fn rusty_pool_example2() { 129 | let pool = rusty_pool::ThreadPool::default(); 130 | 131 | let handle = pool.complete(async { 132 | let a = some_async_fn(4, 6).await; // 10 133 | let b = some_async_fn(a, 3).await; // 13 134 | let c = other_async_fn(b, a).await; // 3 135 | some_async_fn(c, 5).await // 8 136 | }); 137 | assert_eq!(handle.await_complete(), 8); 138 | 139 | let count = Arc::new(AtomicI32::new(0)); 140 | let clone = count.clone(); 141 | pool.spawn(async move { 142 | let a = some_async_fn(3, 6).await; // 9 143 | let b = other_async_fn(a, 4).await; // 5 144 | let c = some_async_fn(b, 7).await; // 12 145 | clone.fetch_add(c, Ordering::SeqCst); 146 | }); 147 | pool.join(); 148 | assert_eq!(count.load(Ordering::SeqCst), 12); 149 | } 150 | 151 | pub fn rusty_pool_example3() { 152 | let pool = rusty_pool::ThreadPool::default(); 153 | for _ in 0..10 { 154 | pool.execute(|| thread::sleep(Duration::from_secs(10))) 155 | } 156 | 157 | // 等待所有线程变得空闲,即所有任务都完成,包括此线程调用join()后由其他线程添加的任务,或者等待超时 158 | pool.join_timeout(Duration::from_secs(5)); 159 | 160 | let count = Arc::new(AtomicI32::new(0)); 161 | for _ in 0..15 { 162 | let clone = count.clone(); 163 | pool.execute(move || { 164 | thread::sleep(Duration::from_secs(5)); 165 | clone.fetch_add(1, Ordering::SeqCst); 166 | }); 167 | } 168 | 169 | // 关闭并删除此“ ThreadPool”的唯一实例(无克隆),导致通道被中断,从而导致所有worker在完成当前工作后退出 170 | pool.shutdown_join(); 171 | assert_eq!(count.load(Ordering::SeqCst), 15); 172 | } 173 | pub fn fast_threadpool_example() -> Result<(), fast_threadpool::ThreadPoolDisconnected> { 174 | let threadpool = 175 | fast_threadpool::ThreadPool::start(ThreadPoolConfig::default(), ()).into_sync_handler(); 176 | assert_eq!(4, threadpool.execute(|_| { 2 + 2 })?); 177 | 178 | 179 | let rt = tokio::runtime::Runtime::new().unwrap(); 180 | rt.block_on(async { 181 | let threadpool = fast_threadpool::ThreadPool::start(ThreadPoolConfig::default(), ()).into_async_handler(); 182 | assert_eq!(4, threadpool.execute(|_| { 2 + 2 }).await.unwrap()); 183 | }); 184 | 185 | 186 | Ok(()) 187 | } 188 | 189 | pub fn scoped_threadpool() { 190 | let mut pool = scoped_threadpool::Pool::new(4); 191 | 192 | let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; 193 | 194 | // Use the threads as scoped threads that can 195 | // reference anything outside this closure 196 | pool.scoped(|s| { 197 | // Create references to each element in the vector ... 198 | for e in &mut vec { 199 | // ... and add 1 to it in a seperate thread 200 | s.execute(move || { 201 | *e += 1; 202 | }); 203 | } 204 | }); 205 | 206 | assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8]); 207 | } 208 | 209 | pub fn scheduled_thread_pool() { 210 | let (sender, receiver) = channel(); 211 | 212 | let pool = scheduled_thread_pool::ScheduledThreadPool::new(4); 213 | let handle = pool.execute_after(Duration::from_millis(1000), move || { 214 | println!("Hello from a scheduled thread!"); 215 | sender.send("done").unwrap(); 216 | }); 217 | 218 | let _ = handle; 219 | receiver.recv().unwrap(); 220 | 221 | let handle = pool.execute_at_fixed_rate(Duration::from_millis(1000), Duration::from_millis(1000), || { 222 | println!("Hello from a scheduled thread!"); 223 | }); 224 | 225 | sleep(Duration::from_secs(5)); 226 | handle.cancel() 227 | } 228 | 229 | // workerpool-rs 230 | pub fn workerpool_rs_example() { 231 | use workerpool_rs::pool::WorkerPool; 232 | 233 | let n_workers = 4; 234 | let n_jobs = 8; 235 | let pool = WorkerPool::new(n_workers); 236 | 237 | let (tx, rx) = channel(); 238 | let atx = Arc::new(Mutex::new(tx)); 239 | for _ in 0..n_jobs { 240 | let atx = atx.clone(); 241 | pool.execute(move || { 242 | let tx = atx.lock().unwrap(); 243 | tx.send(1) 244 | .expect("channel will be there waiting for the pool"); 245 | }); 246 | } 247 | 248 | // assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 249 | println!("{}", rx.iter().take(n_jobs).fold(0, |a, b| a + b)) 250 | } 251 | 252 | fn test(msg: usize) { 253 | println!("key: {}\tvalue: {}", msg, fib(msg)); 254 | } 255 | 256 | // poolite 257 | pub fn poolite_example() { 258 | let pool = poolite::Pool::new().unwrap(); 259 | for i in 0..10 { 260 | pool.push(move || test(i)); 261 | } 262 | 263 | pool.join(); //wait for the pool 264 | } 265 | 266 | pub fn poolite_example2() { 267 | let pool = poolite::Pool::new().unwrap(); 268 | let mut array = (0..10usize).into_iter().map(|i| (i, 0)).collect::>(); 269 | 270 | // scoped method will waiting scoped's task running finish. 271 | pool.scoped(|scope| { 272 | for i in array.iter_mut() { 273 | // have to move 274 | scope.push(move || i.1 = i.0 * i.0); 275 | } 276 | }); 277 | 278 | for (i, j) in array { 279 | println!("key: {}\tvalue: {}", i, j); 280 | } 281 | } 282 | 283 | pub fn executor_service_example() { 284 | use executor_service::Executors; 285 | 286 | let mut executor_service = 287 | Executors::new_fixed_thread_pool(10).expect("Failed to create the thread pool"); 288 | 289 | let counter = Arc::new(AtomicUsize::new(0)); 290 | 291 | for _ in 0..10 { 292 | let counter = counter.clone(); 293 | executor_service.execute(move || { 294 | thread::sleep(Duration::from_millis(100)); 295 | counter.fetch_add(1, Ordering::SeqCst); 296 | }).unwrap(); 297 | } 298 | 299 | thread::sleep(Duration::from_millis(1000)); 300 | 301 | assert_eq!(counter.load(Ordering::SeqCst), 10); 302 | 303 | let mut executor_service = 304 | Executors::new_fixed_thread_pool(2).expect("Failed to create the thread pool"); 305 | 306 | let some_param = "Mr White"; 307 | let res = executor_service 308 | .submit_sync(move || { 309 | sleep(Duration::from_secs(5)); 310 | println!("Hello {:}", some_param); 311 | println!("Long computation finished"); 312 | 2 313 | }) 314 | .expect("Failed to submit function"); 315 | 316 | println!("Result: {:#?}", res); 317 | assert_eq!(res, 2); 318 | } 319 | 320 | pub fn threadpool_executor_example() { 321 | let pool = threadpool_executor::ThreadPool::new(1); 322 | let mut expectation = pool.execute(|| "hello, thread pool!").unwrap(); 323 | assert_eq!(expectation.get_result().unwrap(), "hello, thread pool!"); 324 | 325 | let pool = threadpool_executor::threadpool::Builder::new() 326 | .core_pool_size(1) 327 | .maximum_pool_size(3) 328 | .keep_alive_time(std::time::Duration::from_secs(300)) 329 | .exeed_limit_policy(threadpool_executor::threadpool::ExceedLimitPolicy::Wait) 330 | .build(); 331 | 332 | pool.execute(|| { 333 | std::thread::sleep(std::time::Duration::from_secs(3)); 334 | }) 335 | .unwrap(); 336 | let mut exp = pool.execute(|| {}).unwrap(); 337 | exp.cancel().unwrap(); 338 | } 339 | 340 | pub fn executors_example() { 341 | use executors::*; 342 | 343 | let n_workers = 4; 344 | let n_jobs = 8; 345 | let pool = crossbeam_workstealing_pool::small_pool(n_workers); 346 | 347 | let (tx, rx) = channel(); 348 | for _ in 0..n_jobs { 349 | let tx = tx.clone(); 350 | pool.execute(move || { 351 | tx.send(1) 352 | .expect("channel will be there waiting for the pool"); 353 | }); 354 | } 355 | 356 | assert_eq!(rx.iter().take(n_jobs).fold(0, |a, b| a + b), 8); 357 | } 358 | 359 | // slave-pool 360 | -------------------------------------------------------------------------------- /pool/src/main.rs: -------------------------------------------------------------------------------- 1 | use pool::*; 2 | 3 | fn main() { 4 | rayon_threadpool(); 5 | rayon_threadpool2(); 6 | threadpool_example(); 7 | threadpool_example2(); 8 | scoped_threadpool(); 9 | rusty_pool_example(); 10 | fast_threadpool_example().unwrap(); 11 | scheduled_thread_pool(); 12 | workerpool_rs_example(); 13 | poolite_example(); 14 | poolite_example2(); 15 | executor_service_example(); 16 | threadpool_executor_example(); 17 | executors_example(); 18 | } 19 | -------------------------------------------------------------------------------- /process/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "process" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-process = "1.5.0" 10 | easy_process = "0.2.1" 11 | futures-lite = "1.12.0" 12 | process_control = "4.0.0" 13 | smol = "1.2.5" 14 | subprocess = "0.2.9" 15 | -------------------------------------------------------------------------------- /process/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::process::Command; 3 | use std::process::Stdio; 4 | use std::time::Duration; 5 | 6 | use futures_lite::io::BufReader; 7 | use futures_lite::prelude::*; 8 | use process_control::ChildExt; 9 | use process_control::Control; 10 | 11 | pub fn async_process_example() { 12 | futures_lite::future::block_on(async { 13 | let mut child = async_process::Command::new("find") 14 | .arg(".") 15 | .stdout(Stdio::piped()) 16 | .spawn() 17 | .unwrap(); 18 | 19 | let mut lines = BufReader::new(child.stdout.take().unwrap()).lines(); 20 | 21 | while let Some(line) = lines.next().await { 22 | println!("{}", line.unwrap()); 23 | } 24 | }); 25 | } 26 | 27 | pub fn process_control_example() { 28 | let process = Command::new("echo") 29 | .arg("hello") 30 | .stdout(Stdio::piped()) 31 | .spawn() 32 | .unwrap(); 33 | 34 | let output = process 35 | .controlled_with_output() 36 | .time_limit(Duration::from_secs(1)) 37 | .terminate_for_timeout() 38 | .wait() 39 | .unwrap() 40 | .ok_or_else(|| io::Error::new(io::ErrorKind::TimedOut, "Process timed out")) 41 | .unwrap(); 42 | 43 | assert_eq!(b"hello", &output.stdout[..5]); 44 | } 45 | 46 | pub fn easy_process_example() { 47 | // stdout 48 | if let Ok(output) = easy_process::run(r#"sh -c 'echo "1 2 3 4"'"#) { 49 | assert_eq!(&output.stdout, "1 2 3 4\n"); 50 | } 51 | 52 | 53 | // stderr 54 | if let Ok(output) = easy_process::run(r#"sh -c 'echo "1 2 3 4" >&2'"#) { 55 | assert_eq!(&output.stderr, "1 2 3 4\n"); 56 | } 57 | 58 | } 59 | 60 | pub fn pipe() { 61 | // 创建两个子进程,一个作为生产者,一个作为消费者 62 | 63 | // 生产者进程 64 | let producer = Command::new("echo") 65 | .arg("Hello, Rust!") 66 | .stdout(Stdio::piped()) 67 | .spawn() 68 | .expect("Failed to start producer command"); 69 | 70 | // 消费者进程 71 | let consumer = Command::new("grep") 72 | .arg("Rust") 73 | .stdin(producer.stdout.unwrap()) 74 | .output() 75 | .expect("Failed to start consumer command"); 76 | 77 | // 获取消费者的输出 78 | let output = String::from_utf8_lossy(&consumer.stdout); 79 | println!("Output: {:?}", output); 80 | } 81 | 82 | pub fn spawn_a_process() { 83 | let output = Command::new("echo") 84 | .arg("Hello world") 85 | .output() 86 | .expect("Failed to execute command"); 87 | 88 | assert_eq!(b"Hello world\n", output.stdout.as_slice()); 89 | } 90 | 91 | pub fn process_io() { 92 | let echo_child = Command::new("echo") 93 | .arg("Oh no, a tpyo!") 94 | .stdout(Stdio::piped()) 95 | .spawn() 96 | .expect("Failed to start echo process"); 97 | 98 | let echo_out = echo_child.stdout.expect("Failed to open echo stdout"); 99 | 100 | let sed_child = Command::new("sed") 101 | .arg("s/tpyo/typo/") 102 | .stdin(Stdio::from(echo_out)) 103 | .stdout(Stdio::piped()) 104 | .spawn() 105 | .expect("Failed to start sed process"); 106 | 107 | let output = sed_child.wait_with_output().expect("Failed to wait on sed"); 108 | assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice()); 109 | } 110 | 111 | pub fn child() { 112 | let mut child = Command::new("/bin/cat") 113 | .arg("Cargo.toml") 114 | .spawn() 115 | .expect("failed to execute child"); 116 | 117 | let ecode = child.wait().expect("failed to wait on child"); 118 | 119 | assert!(ecode.success()); 120 | } 121 | 122 | pub fn kill() { 123 | let mut command = Command::new("yes"); 124 | if let Ok(mut child) = command.spawn() { 125 | println!("Child's ID is {}", child.id()); 126 | child.kill().expect("command wasn't running"); 127 | } else { 128 | println!("yes command didn't start"); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /process/src/main.rs: -------------------------------------------------------------------------------- 1 | use process::*; 2 | 3 | fn main() { 4 | spawn_a_process(); 5 | process_io(); 6 | child(); 7 | kill(); 8 | pipe(); 9 | 10 | async_process_example(); 11 | process_control_example(); 12 | easy_process_example(); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /rayon_examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rayon_examples" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rayon = "1.5.3" 10 | -------------------------------------------------------------------------------- /rayon_examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | use rayon::prelude::*; 2 | 3 | pub fn rayon_par_iter() { 4 | let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 5 | let sum = v.par_iter().map(|x| x * x).sum::(); 6 | println!("sum: {}", sum); 7 | 8 | let mut left = vec![42; 10]; 9 | let mut right = vec![-1; 10]; 10 | 11 | (10..15) 12 | .into_par_iter() 13 | .enumerate() 14 | .unzip_into_vecs(&mut left, &mut right); 15 | 16 | assert_eq!(left, [0, 1, 2, 3, 4]); 17 | assert_eq!(right, [10, 11, 12, 13, 14]); 18 | } 19 | 20 | pub fn rayon_scope_example() { 21 | rayon::scope(|s| { 22 | s.spawn(|_| { 23 | println!("Hello from a thread!"); 24 | }); 25 | }); 26 | } 27 | 28 | pub fn rayon_scope_example2() { 29 | let mut value_a = None; 30 | let mut value_b = None; 31 | let mut value_c = None; 32 | rayon::scope(|s| { 33 | s.spawn(|s1| { 34 | value_a = Some(22); 35 | 36 | s1.spawn(|_| { 37 | value_b = Some(44); 38 | }); 39 | }); 40 | 41 | s.spawn(|_| { 42 | value_c = Some(66); 43 | }); 44 | }); 45 | assert_eq!(value_a, Some(22)); 46 | assert_eq!(value_b, Some(44)); 47 | assert_eq!(value_c, Some(66)); 48 | } 49 | 50 | 51 | pub fn rayon_scopefifo_example() { 52 | rayon::scope_fifo(|s| { 53 | s.spawn_fifo(|s| { // task s.1 54 | println!("s.1"); 55 | s.spawn_fifo(|_s| { // task s.1.1 56 | println!("s.1.1"); 57 | rayon::scope_fifo(|t| { 58 | t.spawn_fifo(|_| println!("t.1")); // task t.1 59 | t.spawn_fifo(|_| println!("t.2")); // task t.2 60 | }); 61 | }); 62 | }); 63 | s.spawn_fifo(|_s| { // task s.2 64 | println!("s.2"); 65 | }); 66 | // point mid 67 | }); 68 | } 69 | 70 | pub fn rayon_threadpool_example() { 71 | fn fib(n: usize) -> usize { 72 | if n == 0 || n == 1 { 73 | return n; 74 | } 75 | let (a, b) = rayon::join(|| fib(n - 1), || fib(n - 2)); // runs inside of `pool` 76 | return a + b; 77 | } 78 | 79 | let pool = rayon::ThreadPoolBuilder::new() 80 | .num_threads(4) 81 | .build() 82 | .unwrap(); 83 | 84 | let n = pool.install(|| fib(20)); 85 | 86 | println!("{}", n); 87 | } 88 | 89 | pub fn rayon_global_thread_pool_example() { 90 | rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap(); 91 | } -------------------------------------------------------------------------------- /rayon_examples/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | use rayon_examples::*; 3 | 4 | fn main() { 5 | rayon_par_iter(); 6 | 7 | rayon_scope_example(); 8 | rayon_scope_example2(); 9 | rayon_scopefifo_example(); 10 | rayon_threadpool_example(); 11 | rayon_global_thread_pool_example(); 12 | } 13 | -------------------------------------------------------------------------------- /special/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "special" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | arc-swap = "1.6.0" 10 | async-lock = "2.5.0" 11 | async-oneshot = "0.5.0" 12 | async-weighted-semaphore = "0.2.1" 13 | async_singleflight = "0.5.0" 14 | atomic-waker = "1.1.2" 15 | atomic_float = "0.1.0" 16 | atomicbox = "0.4.0" 17 | atomig = "0.4.0" 18 | awaitgroup = "0.6.0" 19 | barrage = "0.2.3" 20 | catty = "0.1.5" 21 | concurrent-queue = "1.2.4" 22 | crossbeam-utils = "0.8.14" 23 | dashmap = "5.4.0" 24 | event-listener = "2.5.3" 25 | evmap = "10.0.2" 26 | flurry = "0.4.0" 27 | futures = "0.3.25" 28 | oneshot = "0.1.5" 29 | portable-atomic = { version = "0.3", features=["float"] } 30 | process_lock = "0.1.0" 31 | scc = "1.5.0" 32 | sharded-slab = "0.1.4" 33 | simple-mutex = "1.1.5" 34 | singleflight = "0.2.0" 35 | singleflight-async = "0.1.1" 36 | slab = "0.4.7" 37 | smol = "1.2.5" 38 | sync_cow = "0.1.1" 39 | tokio = { version = "1.21.2", features = ["full"] } 40 | triggered = "0.1.2" 41 | triple_buffer = "6.2.0" 42 | try-lock = "0.2.3" 43 | waitgroup = "0.1.2" 44 | wg = "0.3.1" 45 | -------------------------------------------------------------------------------- /special/src/arcswap.rs: -------------------------------------------------------------------------------- 1 | 2 | use arc_swap::ArcSwap; 3 | use std::sync::Arc; 4 | use crossbeam_utils::thread; 5 | 6 | pub fn arc_swap_example() { 7 | let value = ArcSwap::from(Arc::new(5)); 8 | thread::scope(|scope| { 9 | scope.spawn(|_| { 10 | let new_value = Arc::new(4); 11 | value.store(new_value); 12 | }); 13 | for _ in 0..10 { 14 | scope.spawn(|_| { 15 | loop { 16 | let v = value.load(); 17 | println!("value is {}", v); 18 | return; 19 | } 20 | }); 21 | } 22 | }).unwrap() 23 | 24 | } -------------------------------------------------------------------------------- /special/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod oslock; 2 | mod oneshots; 3 | mod map; 4 | mod primitive; 5 | mod notify; 6 | mod queue; 7 | mod scc_examples; 8 | mod sema_examples; 9 | mod singleflight_example; 10 | mod synccow; 11 | mod arcswap; 12 | 13 | pub use oslock::*; 14 | pub use oneshots::*; 15 | pub use map::*; 16 | pub use primitive::*; 17 | pub use notify::*; 18 | pub use queue::*; 19 | pub use scc_examples::*; 20 | pub use sema_examples::*; 21 | pub use singleflight_example::*; 22 | pub use synccow::*; 23 | pub use arcswap::*; -------------------------------------------------------------------------------- /special/src/main.rs: -------------------------------------------------------------------------------- 1 | use special::*; 2 | 3 | 4 | fn main() { 5 | process_lock(); 6 | 7 | try_lock_example1(); 8 | 9 | sharded_slab_read(); 10 | sharded_slab_write(); 11 | sharded_slab_pool(); 12 | slab_example(); 13 | 14 | event_listener_example(); 15 | triggered_example(); 16 | barrage_example(); 17 | 18 | hashmap_example(); 19 | flurry_hashmap(); 20 | flurry_hashset(); 21 | evmap_example(); 22 | 23 | concurrent_queue_example(); 24 | triple_buffer_example(); 25 | 26 | async_lock_mutex(); 27 | async_lock_rwlock(); 28 | async_lock_barrier(); 29 | 30 | portable_atomic_i128(); 31 | portable_atomic_u128(); 32 | portable_atomic_f64(); 33 | atomic_float_example(); 34 | atomig_example(); 35 | atomicbox_examples(); 36 | 37 | simple_mutex_example(); 38 | 39 | oneshot_example(); 40 | async_oneshot_example(); 41 | catty_example(); 42 | 43 | waitgroup_example(); 44 | wg_example(); 45 | awaitgroup_example(); 46 | 47 | scc_hashmap(); 48 | scc_hashindex(); 49 | scc_treeindex(); 50 | scc_hashset(); 51 | scc_queue(); 52 | 53 | 54 | async_lock_semaphore(); 55 | async_weighted_semaphore_example(); 56 | tokio_semaphore_example(); 57 | 58 | singleflight_example(); 59 | async_singleflight_example(); 60 | 61 | sync_cow_example().unwrap(); 62 | arc_swap_example(); 63 | 64 | atomic_waker_example(); 65 | } 66 | 67 | 68 | // lockfree -------------------------------------------------------------------------------- /special/src/map.rs: -------------------------------------------------------------------------------- 1 | use dashmap::DashMap; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | pub fn hashmap_example() { 6 | let map = Arc::new(DashMap::new()); 7 | 8 | let map1 = map.clone(); 9 | let whandle = thread::spawn(move || { 10 | map1.insert(1, 2); 11 | map1.insert(2, 3); 12 | }); 13 | 14 | let map2 = map.clone(); 15 | let rhandle = thread::spawn(move || { 16 | loop { 17 | if let Some(v) = map2.get(&1) { 18 | println!("get value {} for key 1", *v); 19 | break; 20 | } 21 | } 22 | 23 | loop { 24 | if let Some(v) = map2.get(&2) { 25 | println!("get value {} for key 2", *v); 26 | break; 27 | } 28 | } 29 | }); 30 | 31 | whandle.join().unwrap(); 32 | rhandle.join().unwrap(); 33 | } 34 | 35 | pub fn flurry_hashmap() { 36 | let map = flurry::HashMap::new(); 37 | 38 | assert_eq!(map.pin().insert(37, "a"), None); 39 | assert_eq!(map.pin().is_empty(), false); 40 | } 41 | 42 | pub fn flurry_hashset() { 43 | // Initialize a new hash set. 44 | let books = flurry::HashSet::new(); 45 | let guard = books.guard(); 46 | 47 | // Add some books 48 | books.insert("Fight Club", &guard); 49 | books.insert("Three Men In A Raft", &guard); 50 | books.insert("The Book of Dust", &guard); 51 | books.insert("The Dry", &guard); 52 | 53 | // Check for a specific one. 54 | if !books.contains(&"The Drunken Botanist", &guard) { 55 | println!("We don't have The Drunken Botanist."); 56 | } 57 | 58 | // Remove a book. 59 | books.remove(&"Three Men In A Raft", &guard); 60 | 61 | // Iterate over everything. 62 | for book in books.iter(&guard) { 63 | println!("{}", book); 64 | } 65 | } 66 | 67 | pub fn evmap_example() { 68 | let (book_reviews_r, mut book_reviews_w) = evmap::new(); 69 | 70 | let readers: Vec<_> = (0..4) 71 | .map(|_| { 72 | let r = book_reviews_r.clone(); 73 | thread::spawn(move || { 74 | loop { 75 | let l = r.len(); 76 | if l == 0 { 77 | thread::yield_now(); 78 | } else { 79 | // the reader will either see all the reviews, 80 | // or none of them, since refresh() is atomic. 81 | assert_eq!(l, 4); 82 | break; 83 | } 84 | } 85 | }) 86 | }) 87 | .collect(); 88 | 89 | // do some writes 90 | book_reviews_w.insert("Adventures of Huckleberry Finn", "My favorite book."); 91 | book_reviews_w.insert("Grimms' Fairy Tales", "Masterpiece."); 92 | book_reviews_w.insert("Pride and Prejudice", "Very enjoyable."); 93 | book_reviews_w.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); 94 | // expose the writes 95 | book_reviews_w.refresh(); 96 | 97 | // you can read through the write handle 98 | assert_eq!(book_reviews_w.len(), 4); 99 | 100 | // the original read handle still works too 101 | assert_eq!(book_reviews_r.len(), 4); 102 | 103 | // all the threads should eventually see .len() == 4 104 | for r in readers.into_iter() { 105 | assert!(r.join().is_ok()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /special/src/notify.rs: -------------------------------------------------------------------------------- 1 | use event_listener::Event; 2 | use std::sync::atomic::{AtomicBool, Ordering}; 3 | use std::sync::Arc; 4 | use std::thread; 5 | use std::time::Duration; 6 | 7 | pub fn event_listener_example() { 8 | let flag = Arc::new(AtomicBool::new(false)); 9 | let event = Arc::new(Event::new()); 10 | 11 | // Spawn a thread that will set the flag after 1 second. 12 | thread::spawn({ 13 | let flag = flag.clone(); 14 | let event = event.clone(); 15 | move || { 16 | // Wait for a second. 17 | thread::sleep(Duration::from_secs(1)); 18 | 19 | // Set the flag. 20 | flag.store(true, Ordering::SeqCst); 21 | 22 | // Notify all listeners that the flag has been set. 23 | event.notify(usize::MAX); 24 | } 25 | }); 26 | 27 | // Wait until the flag is set. 28 | loop { 29 | // Check the flag. 30 | if flag.load(Ordering::SeqCst) { 31 | break; 32 | } 33 | 34 | // Start listening for events. 35 | let listener = event.listen(); 36 | 37 | // Check the flag again after creating the listener. 38 | if flag.load(Ordering::SeqCst) { 39 | break; 40 | } 41 | 42 | // Wait for a notification and continue the loop. 43 | listener.wait(); 44 | } 45 | 46 | println!("flag is set"); 47 | } 48 | 49 | pub fn triggered_example() { 50 | smol::block_on(async { 51 | let (trigger, listener) = triggered::trigger(); 52 | 53 | let task = smol::spawn(async { 54 | // Blocks until `trigger.trigger()` below 55 | listener.await; 56 | 57 | println!("Triggered async task"); 58 | }); 59 | 60 | // This will make any thread blocked in `Listener::wait()` or async task awaiting the 61 | // listener continue execution again. 62 | trigger.trigger(); 63 | 64 | let _ = task.await; 65 | }) 66 | } 67 | 68 | pub fn barrage_example() { 69 | smol::block_on(async { 70 | let (tx, rx) = barrage::unbounded(); 71 | let rx2 = rx.clone(); 72 | tx.send_async("Hello!").await.unwrap(); 73 | assert_eq!(rx.recv_async().await, Ok("Hello!")); 74 | assert_eq!(rx2.recv_async().await, Ok("Hello!")); 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /special/src/oneshots.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | pub fn oneshot_example() { 4 | let (sender, receiver) = oneshot::channel::(); 5 | let sender = thread::spawn(move || { 6 | sender.send(1).unwrap(); 7 | }); 8 | let receiver = thread::spawn(move || { 9 | let v = receiver.recv().unwrap(); 10 | println!("get value {}", v); 11 | }); 12 | sender.join().unwrap(); 13 | receiver.join().unwrap(); 14 | } 15 | 16 | pub fn async_oneshot_example() { 17 | let (mut sender, receiver) = async_oneshot::oneshot(); 18 | smol::block_on(async { 19 | sender.send(1).unwrap(); 20 | }); 21 | 22 | smol::block_on(async { 23 | let v = receiver.try_recv().unwrap(); 24 | println!("get value {}", v); 25 | }); 26 | } 27 | 28 | pub fn catty_example() { 29 | let (sender, mut receiver) = ::oneshot(); 30 | let sender = thread::spawn(move || { 31 | sender.send(1).unwrap(); 32 | }); 33 | let receiver = thread::spawn(move || { 34 | let v = receiver.try_recv().unwrap(); 35 | if v.is_some() { 36 | println!("get value {}", v.unwrap()); 37 | } 38 | 39 | }); 40 | sender.join().unwrap(); 41 | receiver.join().unwrap(); 42 | } -------------------------------------------------------------------------------- /special/src/oslock.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::time::{Duration, Instant}; 3 | use process_lock::ProcessLock; 4 | 5 | 6 | pub fn process_lock() { 7 | let lock = ProcessLock::new(String::from(".process_lock"), None); 8 | let start = Instant::now(); 9 | loop { 10 | if lock.is_ok() { 11 | println!("lock success"); 12 | break; 13 | } 14 | if start.elapsed() > Duration::from_millis(500) { 15 | println!("lock timeout"); 16 | break; 17 | } 18 | std::thread::sleep(Duration::from_millis(100)); 19 | } 20 | std::thread::sleep(Duration::from_millis(500)); 21 | 22 | } -------------------------------------------------------------------------------- /special/src/primitive/async_lock_examples.rs: -------------------------------------------------------------------------------- 1 | use async_lock::*; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | pub fn async_lock_mutex() { 6 | let lock = Arc::new(Mutex::new(0)); 7 | 8 | let lock1 = lock.clone(); 9 | smol::block_on(async { 10 | let mut guard = lock1.lock().await; 11 | *guard += 1; 12 | }); 13 | 14 | let lock2 = lock.clone(); 15 | smol::block_on(async { 16 | let guard = lock2.lock().await; 17 | println!("lock2 {}", *guard); 18 | }); 19 | } 20 | 21 | pub fn async_lock_rwlock() { 22 | let lock = Arc::new(RwLock::new(0)); 23 | 24 | let lock1 = lock.clone(); 25 | smol::block_on(async { 26 | let mut guard = lock1.write().await; 27 | *guard += 1; 28 | }); 29 | 30 | let lock2 = lock.clone(); 31 | smol::block_on(async { 32 | let guard = lock2.read().await; 33 | println!("lock2 {}", *guard); 34 | }); 35 | } 36 | 37 | pub fn async_lock_barrier() { 38 | let barrier = Arc::new(Barrier::new(5)); 39 | 40 | thread::scope(|s| { 41 | for _ in 0..5 { 42 | let barrier = barrier.clone(); 43 | s.spawn(move || { 44 | smol::block_on(async { 45 | println!("before wait"); 46 | barrier.wait().await; 47 | println!("after wait"); 48 | }); 49 | }); 50 | } 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /special/src/primitive/atomic_examples.rs: -------------------------------------------------------------------------------- 1 | use atomicbox::AtomicBox; 2 | use atomig::Atomic; 3 | use portable_atomic::*; 4 | use std::sync::atomic::Ordering; 5 | use std::sync::atomic::Ordering::Relaxed; 6 | 7 | pub fn portable_atomic_i128() { 8 | let mut some_var = AtomicI128::new(10); 9 | assert_eq!(*some_var.get_mut(), 10); 10 | *some_var.get_mut() = 5; 11 | assert_eq!(some_var.load(Ordering::SeqCst), 5); 12 | 13 | assert_eq!(some_var.load(Ordering::Relaxed), 5); 14 | } 15 | 16 | pub fn portable_atomic_u128() { 17 | let mut some_var = AtomicU128::new(10); 18 | assert_eq!(*some_var.get_mut(), 10); 19 | *some_var.get_mut() = 5; 20 | assert_eq!(some_var.load(Ordering::SeqCst), 5); 21 | 22 | assert_eq!(some_var.load(Ordering::Relaxed), 5); 23 | } 24 | 25 | pub fn portable_atomic_f32() { 26 | let mut some_var = AtomicF32::new(10.0); 27 | assert_eq!(*some_var.get_mut(), 10.0); 28 | *some_var.get_mut() = 5.0; 29 | assert_eq!(some_var.load(Ordering::SeqCst), 5.0); 30 | 31 | assert_eq!(some_var.load(Ordering::Relaxed), 5.0); 32 | } 33 | 34 | pub fn portable_atomic_f64() { 35 | let mut some_var = AtomicF64::new(10.0f64); 36 | assert_eq!(*some_var.get_mut(), 10.0); 37 | *some_var.get_mut() = 5.0; 38 | assert_eq!(some_var.load(Ordering::SeqCst), 5.0); 39 | 40 | assert_eq!(some_var.load(Ordering::Relaxed), 5.0); 41 | } 42 | 43 | pub fn atomic_float_example() { 44 | let some_var = atomic_float::AtomicF32::new(800.0f32); 45 | some_var.fetch_add(30.0, Relaxed); 46 | some_var.fetch_sub(-55.0, Relaxed); 47 | some_var.fetch_neg(Relaxed); 48 | 49 | assert_eq!(some_var.load(Relaxed), -885.0); 50 | 51 | let some_var = atomic_float::AtomicF64::new(800.0f64); 52 | some_var.fetch_add(30.0, Relaxed); 53 | some_var.fetch_sub(-55.0, Relaxed); 54 | some_var.fetch_neg(Relaxed); 55 | 56 | assert_eq!(some_var.load(Relaxed), -885.0); 57 | } 58 | 59 | pub fn atomig_example() { 60 | let some_var = Atomic::new(0); 61 | some_var.store(800, Relaxed); 62 | 63 | some_var.fetch_add(30, Relaxed); 64 | some_var.fetch_sub(-55, Relaxed); 65 | 66 | assert_eq!(some_var.load(Relaxed), 885); 67 | } 68 | 69 | pub fn atomicbox_examples() { 70 | let atom = AtomicBox::new(Box::new("one")); 71 | let mut boxed = Box::new("two"); 72 | atom.swap_mut(&mut boxed, Ordering::AcqRel); 73 | assert_eq!(*boxed, "one"); 74 | } 75 | -------------------------------------------------------------------------------- /special/src/primitive/atomic_waker_examples.rs: -------------------------------------------------------------------------------- 1 | use futures::future::Future; 2 | use futures::task::{Context, Poll, AtomicWaker}; 3 | use std::sync::Arc; 4 | use std::sync::atomic::AtomicBool; 5 | use std::sync::atomic::Ordering::Relaxed; 6 | use std::pin::Pin; 7 | 8 | struct Inner { 9 | waker: AtomicWaker, 10 | set: AtomicBool, 11 | } 12 | 13 | #[derive(Clone)] 14 | struct Flag(Arc); 15 | 16 | impl Flag { 17 | pub fn new() -> Self { 18 | Flag(Arc::new(Inner { 19 | waker: AtomicWaker::new(), 20 | set: AtomicBool::new(false), 21 | })) 22 | } 23 | 24 | pub fn signal(&self) { 25 | self.0.set.store(true, Relaxed); 26 | self.0.waker.wake(); 27 | } 28 | } 29 | 30 | impl Future for Flag { 31 | type Output = bool; 32 | 33 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 34 | // quick check to avoid registration if already done. 35 | if self.0.set.load(Relaxed) { 36 | return Poll::Ready(true); 37 | } 38 | 39 | self.0.waker.register(cx.waker()); 40 | 41 | // Need to check condition **after** `register` to avoid a race 42 | // condition that would result in lost notifications. 43 | if self.0.set.load(Relaxed) { 44 | Poll::Ready(true) 45 | } else { 46 | Poll::Pending 47 | } 48 | } 49 | } 50 | 51 | // extraced from futures::task::AtomicWaker 52 | pub fn atomic_waker_example() { 53 | smol::block_on(async { 54 | let flag = Flag::new(); 55 | let flag2 = flag.clone(); 56 | 57 | smol::spawn(async move { 58 | smol::Timer::after(std::time::Duration::from_secs(1)).await; 59 | flag2.signal(); 60 | }) 61 | .detach(); 62 | 63 | println!("Waiting for flag: {}", flag.await); 64 | }); 65 | } -------------------------------------------------------------------------------- /special/src/primitive/mod.rs: -------------------------------------------------------------------------------- 1 | // usync 2 | 3 | 4 | // waitfor 5 | 6 | // atomig 7 | // atomicbox 8 | 9 | mod try_lock_examples; 10 | mod sharded_slab_example; 11 | mod async_lock_examples; 12 | mod atomic_examples; 13 | mod simple_mutex_examples; 14 | mod waitgroup_examples; 15 | mod atomic_waker_examples; 16 | 17 | pub use try_lock_examples::*; 18 | pub use sharded_slab_example::*; 19 | pub use async_lock_examples::*; 20 | pub use atomic_examples::*; 21 | pub use simple_mutex_examples::*; 22 | pub use waitgroup_examples::*; 23 | pub use atomic_waker_examples::*; 24 | 25 | -------------------------------------------------------------------------------- /special/src/primitive/sharded_slab_example.rs: -------------------------------------------------------------------------------- 1 | use sharded_slab::Pool; 2 | use sharded_slab::Slab; 3 | 4 | use std::sync::{Arc, Mutex}; 5 | 6 | // Slabs provide pre-allocated storage for many instances of a single data type. 7 | // When a large number of values of a single type are required, this can be more efficient than allocating each item individually. 8 | // Since the allocated items are the same size, memory fragmentation is reduced, and creating and removing new items can be very cheap. 9 | 10 | pub fn sharded_slab_read() { 11 | let slab = Arc::new(Slab::new()); 12 | 13 | let slab2 = slab.clone(); 14 | let thread2 = std::thread::spawn(move || { 15 | let key = slab2.insert("hello from thread two").unwrap(); 16 | assert_eq!(slab2.get(key).unwrap(), "hello from thread two"); 17 | key 18 | }); 19 | 20 | let key1 = slab.insert("hello from thread one").unwrap(); 21 | assert_eq!(slab.get(key1).unwrap(), "hello from thread one"); 22 | 23 | // Wait for thread 2 to complete. 24 | let key2 = thread2.join().unwrap(); 25 | 26 | // The item inserted by thread 2 remains in the slab. 27 | assert_eq!(slab.get(key2).unwrap(), "hello from thread two"); 28 | } 29 | 30 | pub fn sharded_slab_write() { 31 | let slab = Arc::new(Slab::new()); 32 | 33 | let key = slab 34 | .insert(Mutex::new(String::from("hello world"))) 35 | .unwrap(); 36 | 37 | let slab2 = slab.clone(); 38 | let thread2 = std::thread::spawn(move || { 39 | let hello = slab2.get(key).expect("item missing"); 40 | let mut hello = hello.lock().expect("mutex poisoned"); 41 | *hello = String::from("hello everyone!"); 42 | }); 43 | 44 | thread2.join().unwrap(); 45 | 46 | let hello = slab.get(key).expect("item missing"); 47 | let hello = hello.lock().expect("mutex poisoned"); 48 | assert_eq!(hello.as_str(), "hello everyone!"); 49 | } 50 | 51 | pub fn sharded_slab_pool() { 52 | let pool: Pool = Pool::new(); 53 | 54 | let mut guard = pool.create().unwrap(); 55 | let key = guard.key(); 56 | guard.push_str("hello world"); 57 | 58 | drop(guard); // release the guard, allowing immutable access. 59 | assert_eq!(pool.get(key).unwrap(), String::from("hello world")); 60 | 61 | // Mark this entry to be cleared. 62 | pool.clear(key); 63 | // The cleared entry is no longer available in the pool 64 | assert!(pool.get(key).is_none()); 65 | } 66 | 67 | pub fn slab_example() { 68 | let mut slab = slab::Slab::new(); 69 | 70 | let hello = slab.insert("hello"); 71 | let world = slab.insert("world"); 72 | 73 | assert_eq!(slab[hello], "hello"); 74 | assert_eq!(slab[world], "world"); 75 | 76 | slab[world] = "earth"; 77 | assert_eq!(slab[world], "earth"); 78 | } 79 | -------------------------------------------------------------------------------- /special/src/primitive/simple_mutex_examples.rs: -------------------------------------------------------------------------------- 1 | use simple_mutex::Mutex; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | pub fn simple_mutex_example() { 6 | let m = Arc::new(Mutex::new(0)); 7 | let mut handles = vec![]; 8 | 9 | for _ in 0..10 { 10 | let m = m.clone(); 11 | handles.push(thread::spawn(move || { 12 | *m.lock() += 1; 13 | })); 14 | } 15 | 16 | for handle in handles { 17 | handle.join().unwrap(); 18 | } 19 | 20 | println!("m = {:?}", m); 21 | } -------------------------------------------------------------------------------- /special/src/primitive/try_lock_examples.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use try_lock::TryLock; 3 | 4 | pub fn try_lock_example1() { 5 | // a thing we want to share 6 | struct Widget { 7 | name: String, 8 | } 9 | 10 | // lock it up! 11 | let widget1 = Arc::new(TryLock::new(Widget { 12 | name: "Spanner".into(), 13 | })); 14 | 15 | let widget2 = widget1.clone(); 16 | 17 | // mutate the widget 18 | let mut locked = widget1.try_lock().expect("example isn't locked yet"); 19 | locked.name.push_str(" Bundle"); 20 | 21 | // hands off, buddy 22 | let not_locked = widget2.try_lock(); 23 | assert!(not_locked.is_none(), "widget1 has the lock"); 24 | 25 | // ok, you can have it 26 | drop(locked); 27 | 28 | let locked2 = widget2.try_lock().expect("widget1 lock is released"); 29 | 30 | assert_eq!(locked2.name, "Spanner Bundle"); 31 | } 32 | -------------------------------------------------------------------------------- /special/src/primitive/waitgroup_examples.rs: -------------------------------------------------------------------------------- 1 | use waitgroup::WaitGroup; 2 | 3 | pub fn waitgroup_example() { 4 | smol::block_on(async { 5 | let wg = WaitGroup::new(); 6 | for _ in 0..100 { 7 | let w = wg.worker(); 8 | let _ = smol::spawn(async move { 9 | // do work 10 | drop(w); // drop w means task finished 11 | }); 12 | } 13 | 14 | wg.wait().await; 15 | }) 16 | } 17 | 18 | pub fn wg_example() { 19 | use std::sync::atomic::{AtomicUsize, Ordering}; 20 | use std::sync::Arc; 21 | use std::thread::{sleep, spawn}; 22 | use std::time::Duration; 23 | use wg::WaitGroup; 24 | 25 | let wg = WaitGroup::new(); 26 | let ctr = Arc::new(AtomicUsize::new(0)); 27 | 28 | for _ in 0..5 { 29 | let ctrx = ctr.clone(); 30 | let t_wg = wg.add(1); 31 | spawn(move || { 32 | // mock some time consuming task 33 | sleep(Duration::from_millis(50)); 34 | ctrx.fetch_add(1, Ordering::Relaxed); 35 | 36 | // mock task is finished 37 | t_wg.done(); 38 | }); 39 | } 40 | 41 | wg.wait(); 42 | assert_eq!(ctr.load(Ordering::Relaxed), 5); 43 | } 44 | 45 | pub fn awaitgroup_example() { 46 | use awaitgroup::WaitGroup; 47 | 48 | smol::block_on(async { 49 | let mut wg = WaitGroup::new(); 50 | for _ in 0..5 { 51 | // Create a new worker. 52 | let worker = wg.worker(); 53 | 54 | let _ = smol::spawn(async { 55 | // Do some work... 56 | 57 | // This task is done all of its work. 58 | worker.done(); 59 | }); 60 | } 61 | 62 | // Block until all other tasks have finished their work. 63 | wg.wait().await; 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /special/src/queue.rs: -------------------------------------------------------------------------------- 1 | use concurrent_queue::ConcurrentQueue; 2 | use std::sync::Arc; 3 | use std::thread; 4 | 5 | use triple_buffer::triple_buffer; 6 | 7 | pub fn concurrent_queue_example() { 8 | let q = Arc::new(ConcurrentQueue::unbounded()); 9 | 10 | let q1 = q.clone(); 11 | let whandle = thread::spawn(move || { 12 | for i in 0..10 { 13 | q1.push(i).unwrap(); 14 | } 15 | }); 16 | 17 | let q2 = q.clone(); 18 | let rhandle = thread::spawn(move || loop { 19 | if let Ok(v) = q2.pop() { 20 | println!("get value {}", v); 21 | } else { 22 | println!("queue closed"); 23 | break; 24 | } 25 | }); 26 | 27 | whandle.join().unwrap(); 28 | rhandle.join().unwrap(); 29 | } 30 | 31 | pub fn triple_buffer_example() { 32 | let (mut buf_input, mut buf_output) = triple_buffer(&0); 33 | 34 | // The producer thread can move a value into the buffer at any time 35 | let producer = std::thread::spawn(move || buf_input.write(42)); 36 | 37 | // The consumer thread can read the latest value at any time 38 | let consumer = std::thread::spawn(move || { 39 | let latest = buf_output.read(); 40 | assert!(*latest == 42 || *latest == 0); 41 | }); 42 | 43 | producer.join().unwrap(); 44 | consumer.join().unwrap(); 45 | } 46 | -------------------------------------------------------------------------------- /special/src/scc_examples.rs: -------------------------------------------------------------------------------- 1 | use scc::*; 2 | use std::collections::hash_map::RandomState; 3 | 4 | pub fn scc_hashmap() { 5 | let hashmap: HashMap = HashMap::with_capacity(1000); 6 | assert_eq!(hashmap.capacity(), 1024); 7 | 8 | let ticket = hashmap.reserve(10000); 9 | assert!(ticket.is_some()); 10 | assert_eq!(hashmap.capacity(), 16384); 11 | for i in 0..16 { 12 | assert!(hashmap.insert(i, i).is_ok()); 13 | } 14 | drop(ticket); 15 | 16 | assert_eq!(hashmap.capacity(), 1024); 17 | } 18 | 19 | pub fn scc_hashindex() { 20 | let hashindex: HashIndex = HashIndex::default(); 21 | 22 | assert!(!hashindex.remove(&1)); 23 | assert!(hashindex.insert(1, 0).is_ok()); 24 | assert!(hashindex.remove(&1)); 25 | } 26 | 27 | pub fn scc_treeindex() { 28 | let treeindex: TreeIndex = TreeIndex::new(); 29 | 30 | assert!(treeindex.insert(1, 10).is_ok()); 31 | assert_eq!(treeindex.insert(1, 11).err().unwrap(), (1, 11)); 32 | assert_eq!(treeindex.read(&1, |_k, v| *v).unwrap(), 10); 33 | } 34 | 35 | pub fn scc_hashset() { 36 | let hashset: HashSet = HashSet::with_capacity(1000); 37 | assert_eq!(hashset.capacity(), 1024); 38 | 39 | let ticket = hashset.reserve(10000); 40 | assert!(ticket.is_some()); 41 | assert_eq!(hashset.capacity(), 16384); 42 | for i in 0..16 { 43 | assert!(hashset.insert(i).is_ok()); 44 | } 45 | drop(ticket); 46 | 47 | assert_eq!(hashset.capacity(), 1024); 48 | } 49 | 50 | pub fn scc_queue() { 51 | let queue: Queue = Queue::default(); 52 | 53 | queue.push(37); 54 | queue.push(3); 55 | queue.push(1); 56 | 57 | assert_eq!(queue.pop().map(|e| **e), Some(37)); 58 | assert_eq!(queue.pop().map(|e| **e), Some(3)); 59 | assert_eq!(queue.pop().map(|e| **e), Some(1)); 60 | assert!(queue.pop().is_none()); 61 | } 62 | -------------------------------------------------------------------------------- /special/src/sema_examples.rs: -------------------------------------------------------------------------------- 1 | use futures::pin_mut; 2 | use futures::poll; 3 | use std::sync::Arc; 4 | 5 | pub fn tokio_semaphore_example() { 6 | let rt = tokio::runtime::Runtime::new().unwrap(); 7 | 8 | rt.block_on(async { 9 | let semaphore = Arc::new(tokio::sync::Semaphore::new(3)); 10 | let mut join_handles = Vec::new(); 11 | 12 | for _ in 0..5 { 13 | let permit = semaphore.clone().acquire_owned().await.unwrap(); 14 | join_handles.push(tokio::spawn(async move { 15 | // perform task... 16 | // explicitly own `permit` in the task 17 | drop(permit); 18 | })); 19 | } 20 | 21 | for handle in join_handles { 22 | handle.await.unwrap(); 23 | } 24 | }); 25 | } 26 | 27 | pub fn async_weighted_semaphore_example() { 28 | smol::block_on(async { 29 | let sem = async_weighted_semaphore::Semaphore::new(1); 30 | let a = sem.acquire(2); 31 | let b = sem.acquire(1); 32 | pin_mut!(a); 33 | pin_mut!(b); 34 | assert!(poll!(&mut a).is_pending()); 35 | assert!(poll!(&mut b).is_pending()); 36 | 37 | sem.release(1); 38 | assert!(poll!(&mut a).is_ready()); 39 | assert!(poll!(&mut b).is_ready()); 40 | }); 41 | } 42 | 43 | pub fn async_lock_semaphore() { 44 | let s = Arc::new(async_lock::Semaphore::new(2)); 45 | 46 | let _g1 = s.try_acquire_arc().unwrap(); 47 | let g2 = s.try_acquire_arc().unwrap(); 48 | 49 | assert!(s.try_acquire_arc().is_none()); 50 | drop(g2); 51 | assert!(s.try_acquire_arc().is_some()); 52 | } 53 | -------------------------------------------------------------------------------- /special/src/singleflight_example.rs: -------------------------------------------------------------------------------- 1 | use futures::future::join_all; 2 | use singleflight_async::SingleFlight; 3 | use std::sync::Arc; 4 | 5 | use async_singleflight::Group; 6 | 7 | pub fn singleflight_example() { 8 | smol::block_on(async { 9 | let group = SingleFlight::new(); 10 | let mut futures = Vec::new(); 11 | for _ in 0..10 { 12 | futures.push(group.work("key", || async { 13 | println!("will sleep to simulate async task"); 14 | smol::Timer::after(std::time::Duration::from_millis(100)).await; 15 | println!("real task done"); 16 | "my-result" 17 | })); 18 | } 19 | 20 | for fut in futures.into_iter() { 21 | assert_eq!(fut.await, "my-result"); 22 | println!("task finished"); 23 | } 24 | }); 25 | } 26 | 27 | const RES: usize = 7; 28 | 29 | async fn expensive_fn() -> Result { 30 | smol::Timer::after(std::time::Duration::from_millis(100)).await; 31 | Ok(RES) 32 | } 33 | 34 | pub fn async_singleflight_example() { 35 | smol::block_on(async { 36 | let g = Arc::new(Group::<_, ()>::new()); 37 | let mut handlers = Vec::new(); 38 | for _ in 0..10 { 39 | let g = g.clone(); 40 | handlers.push(smol::spawn(async move { 41 | let res = g.work("key", expensive_fn()).await.0; 42 | let r = res.unwrap(); 43 | println!("{}", r); 44 | })); 45 | 46 | } 47 | 48 | join_all(handlers).await; 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /special/src/synccow.rs: -------------------------------------------------------------------------------- 1 | use sync_cow::SyncCow; 2 | use std::sync::Arc; 3 | use std::any::Any; 4 | 5 | 6 | pub fn sync_cow_example() -> Result<(),Box> { 7 | let cow = Arc::new(SyncCow::new(5)); 8 | 9 | // Arc is only needed to pass the ref to the threads 10 | let cow_write_arc = cow.clone(); 11 | let cow_read_arc = cow.clone(); 12 | let cow_result_arc = cow.clone(); 13 | 14 | let writer = std::thread::spawn(move || { 15 | let cow = &*cow_write_arc; // unpack immediately to avoid Arc deref 16 | let mut val = 0; 17 | cow.edit(|x| { 18 | val = *x; 19 | *x = 4; 20 | }); 21 | println!("Cow was {} when writing", val); 22 | }); 23 | 24 | let reader = std::thread::spawn(move || { 25 | let cow = &*cow_read_arc; // unpack immediately to avoid Arc deref 26 | println!("Cow was {} when reading", cow.read()); 27 | }); 28 | 29 | writer.join()?; 30 | reader.join()?; 31 | 32 | let cow = &*cow_result_arc; // unpack immediately to avoid Arc deref 33 | println!("Cow was {} when result", cow.read()); 34 | 35 | Ok(()) 36 | } -------------------------------------------------------------------------------- /sync_primitive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sync_primitive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | once_cell = "1.18.0" 10 | rand = "0.8.5" 11 | -------------------------------------------------------------------------------- /sync_primitive/src/arc.rs: -------------------------------------------------------------------------------- 1 | use std::cell::SyncUnsafeCell; 2 | use std::ops::Deref; 3 | use std::sync::atomic::{AtomicUsize, Ordering}; 4 | use std::sync::Arc; 5 | use std::thread; 6 | 7 | // A thread-safe reference-counting pointer. ‘Arc’ stands for ‘Atomically Reference Counted’. 8 | // Unlike Rc, Arc uses atomic operations for its reference counting. This means that it is thread-safe. 9 | 10 | pub fn arc_example() { 11 | let five = Arc::new(5); 12 | 13 | for _ in 0..10 { 14 | let five = Arc::clone(&five); 15 | 16 | thread::spawn(move || { 17 | println!("{five:?}"); 18 | }); 19 | } 20 | } 21 | 22 | pub fn arc_example2() { 23 | let val = Arc::new(AtomicUsize::new(5)); 24 | 25 | for _ in 0..10 { 26 | let val = Arc::clone(&val); 27 | 28 | thread::spawn(move || { 29 | let v = val.fetch_add(1, Ordering::SeqCst); 30 | println!("{v:?}"); 31 | }); 32 | } 33 | } 34 | 35 | pub fn arc_example3() { 36 | let val = Arc::new(SyncUnsafeCell::new(5)); 37 | let val2 = &val.clone(); 38 | 39 | let mut handles = vec![]; 40 | 41 | for _ in 0..10 { 42 | let val = Arc::clone(&val); 43 | 44 | let handle = thread::spawn(move || { 45 | let v = val.deref().get(); 46 | unsafe {*v += *v}; 47 | }); 48 | 49 | handles.push(handle); 50 | } 51 | 52 | for handle in handles { 53 | handle.join().unwrap(); 54 | } 55 | 56 | unsafe { 57 | let v = val2.deref().get().read(); 58 | println!("SyncUnsafeCell: {:?}", v); 59 | } 60 | 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /sync_primitive/src/atomic.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::atomic::{AtomicUsize, AtomicI32, Ordering}; 3 | use std::{hint, thread}; 4 | 5 | pub fn atomic_example() { 6 | let spinlock = Arc::new(AtomicUsize::new(1)); 7 | 8 | let spinlock_clone = Arc::clone(&spinlock); 9 | let thread = thread::spawn(move|| { 10 | spinlock_clone.store(0, Ordering::SeqCst); 11 | }); 12 | 13 | // Wait for the other thread to release the lock 14 | while spinlock.load(Ordering::SeqCst) != 0 { 15 | hint::spin_loop(); 16 | } 17 | 18 | if let Err(panic) = thread.join() { 19 | println!("Thread had an error: {panic:?}"); 20 | } else { 21 | println!("atomic result: {}", spinlock.load(Ordering::SeqCst)); 22 | } 23 | } 24 | 25 | pub fn atomic_example2() { 26 | let v = AtomicI32::new(5); 27 | 28 | v.store(100, Ordering::SeqCst); 29 | 30 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 31 | println!("atomic swap:{}", v.swap(5, Ordering::SeqCst)); 32 | println!("atomic swap:{}", v.compare_exchange(5,100, Ordering::SeqCst,Ordering::SeqCst).unwrap()); 33 | println!("atomic fetch_add:{}", v.fetch_add(1, Ordering::SeqCst)); 34 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 35 | println!("atomic fetch_sub:{}", v.fetch_sub(1, Ordering::SeqCst)); 36 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 37 | println!("atomic fetch_and:{}", v.fetch_and(1, Ordering::SeqCst)); 38 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 39 | println!("atomic fetch_or:{}", v.fetch_or(1, Ordering::SeqCst)); 40 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 41 | println!("atomic fetch_xor:{}", v.fetch_xor(1, Ordering::SeqCst)); 42 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 43 | println!("atomic fetch_nand:{}", v.fetch_nand(1, Ordering::SeqCst)); 44 | println!("atomic load:{}", v.load(Ordering::SeqCst)); 45 | 46 | } -------------------------------------------------------------------------------- /sync_primitive/src/barrier.rs: -------------------------------------------------------------------------------- 1 | use core::time; 2 | use std::sync::Arc; 3 | use std::sync::Barrier; 4 | use std::thread; 5 | 6 | use rand::Rng; 7 | 8 | pub fn barrier_example() { 9 | let barrier = Arc::new(Barrier::new(10)); 10 | let mut handles = vec![]; 11 | 12 | for _ in 0..10 { 13 | let barrier = barrier.clone(); 14 | handles.push(thread::spawn(move || { 15 | println!("before wait"); 16 | let dur = rand::thread_rng().gen_range(100..1000); 17 | thread::sleep(std::time::Duration::from_millis(dur)); 18 | 19 | barrier.wait(); 20 | 21 | println!("after wait"); 22 | })); 23 | } 24 | 25 | for handle in handles { 26 | handle.join().unwrap(); 27 | } 28 | } 29 | 30 | pub fn barrier_recycle_example() { 31 | let barrier = Arc::new(Barrier::new(10)); 32 | let mut handles = vec![]; 33 | 34 | for _ in 0..10 { 35 | let barrier = barrier.clone(); 36 | handles.push(thread::spawn(move || { 37 | println!("before wait1"); 38 | let dur = rand::thread_rng().gen_range(100..1000); 39 | thread::sleep(std::time::Duration::from_millis(dur)); 40 | 41 | //step1 42 | barrier.wait(); 43 | println!("after wait1"); 44 | thread::sleep(time::Duration::from_secs(1)); 45 | 46 | //step2 47 | barrier.wait(); 48 | println!("after wait2"); 49 | })); 50 | } 51 | 52 | for handle in handles { 53 | handle.join().unwrap(); 54 | } 55 | } -------------------------------------------------------------------------------- /sync_primitive/src/cond.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::Condvar; 3 | use std::sync::Mutex; 4 | use std::thread; 5 | 6 | pub fn condvar_example() { 7 | let condvar = Arc::new(Condvar::new()); 8 | let mutex = Arc::new(Mutex::new(0)); 9 | let mut handles = vec![]; 10 | 11 | for _ in 0..10 { 12 | let condvar = condvar.clone(); 13 | let mutex = mutex.clone(); 14 | handles.push(thread::spawn(move || { 15 | let mut num = mutex.lock().unwrap(); 16 | *num += 1; 17 | println!("num1: {}", num); 18 | condvar.notify_one(); 19 | })); 20 | } 21 | 22 | for _ in 0..10 { 23 | let condvar = condvar.clone(); 24 | let mutex = mutex.clone(); 25 | handles.push(thread::spawn(move || { 26 | let mut num = mutex.lock().unwrap(); 27 | while *num == 0 { 28 | num = condvar.wait(num).unwrap(); 29 | } 30 | *num += 1; 31 | println!("num2: {}", num); 32 | })); 33 | } 34 | 35 | for handle in handles { 36 | handle.join().unwrap(); 37 | } 38 | 39 | println!("Condvar: {}", *mutex.lock().unwrap()); 40 | } 41 | 42 | pub fn condvar_example2() { 43 | let pair = Arc::new((Mutex::new(false), Condvar::new())); 44 | let pair2 = Arc::clone(&pair); 45 | 46 | thread::spawn(move || { 47 | let (lock, cvar) = &*pair2; 48 | let mut started = lock.lock().unwrap(); 49 | *started = true; 50 | // We notify the condvar that the value has changed. 51 | cvar.notify_all(); 52 | }); 53 | 54 | // Wait for the thread to start up. 55 | let (lock, cvar) = &*pair; 56 | let mut started = lock.lock().unwrap(); 57 | // As long as the value inside the `Mutex` is `false`, we wait. 58 | // or 59 | // let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap(); 60 | while !*started { 61 | started = cvar.wait(started).unwrap(); 62 | } 63 | 64 | 65 | println!("condvar_example2 finished"); 66 | } 67 | -------------------------------------------------------------------------------- /sync_primitive/src/exclusive.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Exclusive; 2 | 3 | pub fn exclusive_lock_example() { 4 | let mut exclusive = Exclusive::new(92); 5 | println!("ready"); 6 | std::thread::spawn(move || { 7 | let counter = exclusive.get_mut(); 8 | println!("{}", *counter); 9 | *counter = 100; 10 | }).join().unwrap(); 11 | 12 | } -------------------------------------------------------------------------------- /sync_primitive/src/lazy.rs: -------------------------------------------------------------------------------- 1 | use std::cell::LazyCell; 2 | use std::sync::LazyLock; 3 | 4 | pub fn lazy_cell_example() { 5 | let lazy: LazyCell = LazyCell::new(|| { 6 | println!("initializing"); 7 | 92 8 | }); 9 | println!("ready"); 10 | println!("{}", *lazy); 11 | println!("{}", *lazy); 12 | } 13 | 14 | use std::collections::HashMap; 15 | static HASHMAP: LazyLock> = LazyLock::new(|| { 16 | println!("initializing"); 17 | let mut m = HashMap::new(); 18 | m.insert(13, "Spica".to_string()); 19 | m.insert(74, "Hoyten".to_string()); 20 | m 21 | }); 22 | 23 | pub fn lazy_lock_example() { 24 | println!("ready"); 25 | std::thread::spawn(|| { 26 | println!("{:?}", HASHMAP.get(&13)); 27 | }).join().unwrap(); 28 | println!("{:?}", HASHMAP.get(&74)); 29 | } -------------------------------------------------------------------------------- /sync_primitive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(sync_unsafe_cell)] 2 | #![feature(lazy_cell)] 3 | #![feature(exclusive_wrapper)] 4 | 5 | pub mod arc; 6 | pub mod mutex; 7 | pub mod rwlock; 8 | pub mod once; 9 | pub mod barrier; 10 | pub mod cond; 11 | pub mod mpsc; 12 | pub mod atomic; 13 | pub mod lazy; 14 | pub mod exclusive; 15 | 16 | pub use arc::*; 17 | pub use mutex::*; 18 | pub use rwlock::*; 19 | pub use once::*; 20 | pub use barrier::*; 21 | pub use cond::*; 22 | pub use mpsc::*; 23 | pub use atomic::*; 24 | pub use lazy::*; 25 | pub use exclusive::*; -------------------------------------------------------------------------------- /sync_primitive/src/main.rs: -------------------------------------------------------------------------------- 1 | use sync_primitive::*; 2 | 3 | fn main() { 4 | arc_example(); 5 | arc_example2(); 6 | arc_example3(); 7 | 8 | mutex_example1(); 9 | mutex_example2_poison(); 10 | mutex_example3_drop(); 11 | 12 | rwlock_example(); 13 | read_after_write(); 14 | 15 | once_example(); 16 | oncecell_example(); 17 | oncelock_example(); 18 | once_cell_example(); 19 | 20 | barrier_example(); 21 | barrier_recycle_example(); 22 | 23 | condvar_example(); 24 | condvar_example2(); 25 | 26 | mpsc_example(); 27 | sync_channel_example(); 28 | 29 | atomic_example(); 30 | atomic_example2(); 31 | 32 | lazy_cell_example(); 33 | lazy_lock_example(); 34 | 35 | exclusive_lock_example(); 36 | } 37 | -------------------------------------------------------------------------------- /sync_primitive/src/mpsc.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use std::sync::mpsc; 3 | use std::thread; 4 | use std::time::Duration; 5 | 6 | pub fn mpsc_example() { 7 | let (tx, rx) = mpsc::channel(); 8 | let mut handles = vec![]; 9 | 10 | for i in 0..10 { 11 | let tx = tx.clone(); 12 | handles.push(thread::spawn(move || { 13 | let dur = rand::thread_rng().gen_range(100..1000); 14 | thread::sleep(Duration::from_millis(dur)); 15 | tx.send(i).unwrap(); 16 | })); 17 | } 18 | 19 | thread::spawn(|| { 20 | for handle in handles { 21 | handle.join().unwrap(); 22 | } 23 | drop(tx) 24 | }); 25 | 26 | for i in rx { 27 | println!("MPSC: {}", i); 28 | } 29 | } 30 | 31 | pub fn sync_channel_example() { 32 | let (tx, rx) = mpsc::sync_channel::(0); 33 | thread::spawn(move || { 34 | tx.send(53).unwrap(); 35 | }); 36 | 37 | println!("SyncChannel: {}", rx.recv().unwrap()); 38 | } 39 | -------------------------------------------------------------------------------- /sync_primitive/src/mutex.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | use std::thread; 3 | 4 | pub fn mutex_example1() { 5 | let five = Arc::new(Mutex::new(5)); 6 | 7 | let mut handles = vec![]; 8 | 9 | for _ in 0..10 { 10 | let five = five.clone(); 11 | 12 | let handle = thread::spawn(move || { 13 | let mut five = five.lock().unwrap(); 14 | *five += *five; 15 | }); 16 | 17 | handles.push(handle); 18 | } 19 | 20 | for handle in handles { 21 | handle.join().unwrap(); 22 | } 23 | 24 | println!("Mutex: {:?}", five.lock().unwrap()); 25 | } 26 | 27 | pub fn mutex_example2_poison() { 28 | let lock = Arc::new(Mutex::new(0_u32)); 29 | let lock2 = Arc::clone(&lock); 30 | 31 | let _ = thread::spawn(move || -> () { 32 | // This thread will acquire the mutex first, unwrapping the result of 33 | // `lock` because the lock has not been poisoned. 34 | let _guard = lock2.lock().unwrap(); 35 | 36 | // This panic while holding the lock (`_guard` is in scope) will poison 37 | // the mutex. 38 | panic!(); 39 | }) 40 | .join(); 41 | 42 | // The lock is poisoned by this point, but the returned result can be 43 | // pattern matched on to return the underlying guard on both branches. 44 | let mut guard = match lock.lock() { 45 | Ok(guard) => guard, 46 | Err(poisoned) => poisoned.into_inner(), 47 | }; 48 | 49 | *guard += 1; 50 | } 51 | 52 | pub fn mutex_example3_drop() { 53 | let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4])); 54 | let res_mutex = Arc::new(Mutex::new(0)); 55 | 56 | let mut threads = Vec::with_capacity(3); 57 | (0..3).for_each(|_| { 58 | let data_mutex_clone = Arc::clone(&data_mutex); 59 | let res_mutex_clone = Arc::clone(&res_mutex); 60 | 61 | threads.push(thread::spawn(move || { 62 | let mut data = data_mutex_clone.lock().unwrap(); 63 | // This is the result of some important and long-ish work. 64 | let result = data.iter().fold(0, |acc, x| acc + x * 2); 65 | data.push(result); 66 | drop(data); 67 | 68 | *res_mutex_clone.lock().unwrap() += result; 69 | })); 70 | }); 71 | 72 | let mut data = data_mutex.lock().unwrap(); 73 | // This is the result of some important and long-ish work. 74 | let result = data.iter().fold(0, |acc, x| acc + x * 2); 75 | data.push(result); 76 | drop(data); 77 | *res_mutex.lock().unwrap() += result; 78 | 79 | threads.into_iter().for_each(|thread| { 80 | thread 81 | .join() 82 | .expect("The thread creating or execution failed !") 83 | }); 84 | 85 | println!("Result: {:?}", res_mutex.lock().unwrap()); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /sync_primitive/src/once.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | #![allow(unused_assignments)] 3 | 4 | use std::sync::Once; 5 | use std::sync::OnceLock; 6 | use std::cell::OnceCell; 7 | use std::thread::sleep; 8 | use std::time::Duration; 9 | 10 | pub fn once_example() { 11 | let once = Once::new(); 12 | let mut val: usize = 0; 13 | 14 | once.call_once(|| { 15 | val = 100; 16 | }); 17 | 18 | if once.is_completed() { 19 | println!("Once: {}", val); 20 | } 21 | 22 | } 23 | 24 | pub fn oncecell_example() { 25 | let cell = OnceCell::new(); 26 | assert!(cell.get().is_none()); 27 | 28 | let value: &String = cell.get_or_init(|| { 29 | "Hello, World!".to_string() 30 | }); 31 | assert_eq!(value, "Hello, World!"); 32 | assert!(cell.get().is_some()); 33 | 34 | println!("OnceCell: {}", cell.get().is_some()) 35 | } 36 | 37 | pub fn oncelock_example() { 38 | static CELL: OnceLock = OnceLock::new(); 39 | assert!(CELL.get().is_none()); 40 | 41 | std::thread::spawn(|| { 42 | let value: &String = CELL.get_or_init(|| { 43 | "Hello, World!".to_string() 44 | }); 45 | assert_eq!(value, "Hello, World!"); 46 | }).join().unwrap(); 47 | 48 | 49 | sleep(Duration::from_secs(1)); 50 | 51 | let value: Option<&String> = CELL.get(); 52 | assert!(value.is_some()); 53 | assert_eq!(value.unwrap().as_str(), "Hello, World!"); 54 | 55 | println!("OnceLock: {}", value.is_some()) 56 | } 57 | 58 | use std::{sync::Mutex, collections::HashMap}; 59 | use once_cell::sync::Lazy; 60 | static GLOBAL_DATA: Lazy>> = Lazy::new(|| { 61 | let mut m = HashMap::new(); 62 | m.insert(13, "Spica".to_string()); 63 | m.insert(74, "Hoyten".to_string()); 64 | Mutex::new(m) 65 | }); 66 | 67 | pub fn once_cell_example() { 68 | println!("{:?}", GLOBAL_DATA.lock().unwrap()); 69 | } -------------------------------------------------------------------------------- /sync_primitive/src/rwlock.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::Arc; 3 | use std::sync::RwLock; 4 | use std::thread; 5 | 6 | pub fn rwlock_example() { 7 | let rwlock = Arc::new(RwLock::new(0)); 8 | let mut handles = vec![]; 9 | 10 | for _ in 0..10 { 11 | let rwlock = rwlock.clone(); 12 | handles.push(thread::spawn(move || { 13 | let num = rwlock.read().unwrap(); 14 | println!("num1: {}", num); 15 | })); 16 | } 17 | 18 | for _ in 0..10 { 19 | let rwlock = rwlock.clone(); 20 | handles.push(thread::spawn(move || { 21 | let mut num = rwlock.write().unwrap(); 22 | *num += 1; 23 | })); 24 | } 25 | for _ in 0..10 { 26 | let rwlock = rwlock.clone(); 27 | handles.push(thread::spawn(move || { 28 | let num = rwlock.read().unwrap(); 29 | println!("num2: {}", num); 30 | })); 31 | } 32 | 33 | for handle in handles { 34 | handle.join().unwrap(); 35 | } 36 | 37 | println!("RwLock: {}", *rwlock.read().unwrap()); 38 | } 39 | pub fn read_after_write() { 40 | // 创建一个可共享的可变整数,使用RwLock包装 41 | let counter = Arc::new(RwLock::new(0)); 42 | 43 | // 创建一个线程持有读锁 44 | let read_handle = { 45 | let counter = counter.clone(); 46 | thread::spawn(move || { 47 | // 获取读锁 48 | let num = counter.read().unwrap(); 49 | println!("Reader#1: {}", *num); 50 | 51 | // 休眠模拟读取操作 52 | thread::sleep(std::time::Duration::from_secs(10)); 53 | }) 54 | }; 55 | 56 | // 创建一个线程请求写锁 57 | let write_handle = { 58 | let counter = counter.clone(); 59 | thread::spawn(move || { 60 | // 休眠一小段时间,确保读锁已经被获取 61 | thread::sleep(std::time::Duration::from_secs(1)); 62 | 63 | // 尝试获取写锁 64 | let mut num = counter.write().unwrap(); 65 | *num += 1; 66 | println!("Writer : Incremented counter to {}", *num); 67 | }) 68 | }; 69 | 70 | // 创建一个线程请求读锁 71 | let read_handle_2 = { 72 | let counter = counter.clone(); 73 | thread::spawn(move || { 74 | // 休眠一小段时间,确保写锁已经被获取 75 | thread::sleep(std::time::Duration::from_secs(2)); 76 | 77 | // 尝试获取读锁 78 | let num = counter.read().unwrap(); 79 | println!("Reader#2: {}", *num); 80 | }) 81 | }; 82 | 83 | // 等待读取线程和写入线程完成 84 | read_handle.join().unwrap(); 85 | write_handle.join().unwrap(); 86 | read_handle_2.join().unwrap(); 87 | } -------------------------------------------------------------------------------- /thread/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /thread/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thread" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | send_wrapper = "0.6.0" 10 | thread-priority = "0.9.2" 11 | thread-amount = "0.1.3" 12 | crossbeam = "0.8.2" 13 | thread-control = "0.1.2" 14 | rayon = "1.5.3" 15 | go-spawn = "0.1.2" 16 | num_threads = "0.1.6" 17 | parking = "2.0.0" 18 | num_cpus = "1.13.1" 19 | scopeguard = "1.2.0" 20 | 21 | [target.'cfg(any(windows, linux))'.dependencies] 22 | affinity = "0.1.2" 23 | -------------------------------------------------------------------------------- /thread/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod threads; 2 | 3 | pub use threads::*; 4 | 5 | pub fn panic_example() { 6 | println!("Hello, world!"); 7 | 8 | let h = std::thread::spawn(|| { 9 | std::thread::sleep(std::time::Duration::from_millis(1000)); 10 | panic!("boom"); 11 | }); 12 | 13 | let r = h.join(); 14 | match r { 15 | Ok(r) => println!("All is well! {:?}", r), 16 | Err(e) => println!("Got an error! {:?}", e), 17 | } 18 | 19 | println!("Exiting main!") 20 | } 21 | 22 | 23 | pub fn panic_caught_example() { 24 | println!("Hello, panic_caught_example !"); 25 | 26 | let h = std::thread::spawn(|| { 27 | std::thread::sleep(std::time::Duration::from_millis(1000)); 28 | let result = std::panic::catch_unwind(|| { 29 | panic!("boom"); 30 | }); 31 | 32 | println!("panic caught, result = {}", result.is_err()); 33 | }); 34 | 35 | let r = h.join(); 36 | match r { 37 | Ok(r) => println!("All is well! {:?}", r), 38 | Err(e) => println!("Got an error! {:?}", e), 39 | } 40 | 41 | println!("Exiting main!") 42 | } 43 | 44 | -------------------------------------------------------------------------------- /thread/src/main.rs: -------------------------------------------------------------------------------- 1 | use thread::*; 2 | 3 | fn main() { 4 | start_one_thread(); 5 | start_one_thread_result(); 6 | start_two_threads(); 7 | start_n_threads(); 8 | 9 | current_thread(); 10 | 11 | start_thread_with_sleep(); 12 | start_thread_with_yield_now(); 13 | 14 | start_thread_with_priority(); 15 | thread_builder(); 16 | 17 | start_one_thread_with_move(); 18 | 19 | start_threads_with_threadlocal(); 20 | 21 | thread_park(); 22 | thread_park2(); 23 | thread_park_timeout(); 24 | 25 | start_scoped_threads(); 26 | crossbeam_scope(); 27 | rayon_scope(); 28 | 29 | send_wrapper(); 30 | 31 | print_thread_amount(); 32 | 33 | control_thread(); 34 | 35 | #[cfg(not(target_os = "macos"))] 36 | use_affinity(); 37 | 38 | go_thread(); 39 | scopeguard_defer(); 40 | 41 | park_thread(); 42 | 43 | panic_example(); 44 | panic_caught_example(); 45 | 46 | info(); 47 | 48 | join_all_example(); 49 | } 50 | -------------------------------------------------------------------------------- /thread/src/threads.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::ops::Deref; 3 | use std::rc::Rc; 4 | use std::sync::atomic::{AtomicI64, Ordering}; 5 | use std::sync::mpsc::channel; 6 | use std::sync::Arc; 7 | use std::thread; 8 | use std::time::Duration; 9 | 10 | use crossbeam::thread as crossbeam_thread; 11 | use go_spawn::{go, join}; 12 | use parking::Parker; 13 | use rayon; 14 | use send_wrapper::SendWrapper; 15 | use thread_amount::thread_amount; 16 | use thread_control::*; 17 | use thread_priority::*; 18 | use scopeguard::{guard, defer,defer_on_unwind, defer_on_success}; 19 | 20 | #[cfg(not(target_os = "macos"))] 21 | use affinity::*; 22 | 23 | pub fn start_one_thread() { 24 | let count = thread::available_parallelism().unwrap().get(); 25 | 26 | println!("available_parallelism: {}", count); 27 | 28 | let handle = thread::spawn(|| { 29 | println!("Hello from a thread!"); 30 | }); 31 | 32 | handle.join().unwrap(); 33 | } 34 | 35 | pub fn start_one_thread_result() { 36 | let handle = thread::spawn(|| { 37 | println!("Hello from a thread!"); 38 | 200 39 | }); 40 | 41 | match handle.join() { 42 | Ok(v) => println!("thread result: {}", v), 43 | Err(e) => println!("error: {:?}", e), 44 | } 45 | } 46 | 47 | pub fn start_two_threads() { 48 | let handle1 = thread::spawn(|| { 49 | println!("Hello from a thread1!"); 50 | }); 51 | 52 | let handle2 = thread::spawn(|| { 53 | println!("Hello from a thread2!"); 54 | }); 55 | 56 | handle1.join().unwrap(); 57 | handle2.join().unwrap(); 58 | } 59 | 60 | 61 | pub fn start_n_threads() { 62 | const N: isize = 10; 63 | 64 | let handles: Vec<_> = (0..N) 65 | .map(|i| { 66 | thread::spawn(move || { 67 | println!("Hello from a thread{}!", i); 68 | }) 69 | }) 70 | .collect(); 71 | 72 | // handles.into_iter().for_each(|h| h.join().unwrap()); 73 | 74 | for handle in handles { 75 | handle.join().unwrap(); 76 | } 77 | } 78 | 79 | pub fn current_thread() { 80 | let current_thread = thread::current(); 81 | println!( 82 | "current thread: {:?},{:?}", 83 | current_thread.id(), 84 | current_thread.name() 85 | ); 86 | 87 | let builder = thread::Builder::new() 88 | .name("foo".into()) // set thread name 89 | .stack_size(32 * 1024); // set stack size 90 | 91 | let handler = builder 92 | .spawn(|| { 93 | let current_thread = thread::current(); 94 | println!( 95 | "child thread: {:?},{:?}", 96 | current_thread.id(), 97 | current_thread.name() 98 | ); 99 | }) 100 | .unwrap(); 101 | 102 | handler.join().unwrap(); 103 | } 104 | 105 | pub fn start_thread_with_sleep() { 106 | let handle1 = thread::spawn(|| { 107 | thread::sleep(Duration::from_millis(2000)); 108 | println!("Hello from a thread3!"); 109 | }); 110 | 111 | let handle2 = thread::spawn(|| { 112 | thread::sleep(Duration::from_millis(1000)); 113 | println!("Hello from a thread4!"); 114 | }); 115 | 116 | handle1.join().unwrap(); 117 | handle2.join().unwrap(); 118 | } 119 | 120 | pub fn start_thread_with_yield_now() { 121 | let handle1 = thread::spawn(|| { 122 | thread::yield_now(); 123 | println!("yield_now!"); 124 | }); 125 | 126 | let handle2 = thread::spawn(|| { 127 | thread::yield_now(); 128 | println!("yield_now in another thread!"); 129 | }); 130 | 131 | handle1.join().unwrap(); 132 | handle2.join().unwrap(); 133 | } 134 | 135 | pub fn start_thread_with_priority() { 136 | let handle1 = thread::spawn(|| { 137 | assert!(set_current_thread_priority(ThreadPriority::Min).is_ok()); 138 | println!("Hello from a thread5!"); 139 | }); 140 | 141 | let handle2 = thread::spawn(|| { 142 | assert!(set_current_thread_priority(ThreadPriority::Max).is_ok()); 143 | println!("Hello from a thread6!"); 144 | }); 145 | 146 | handle1.join().unwrap(); 147 | handle2.join().unwrap(); 148 | } 149 | 150 | pub fn thread_builder() { 151 | let thread1 = ThreadBuilder::default() 152 | .name("MyThread") 153 | .priority(ThreadPriority::Max) 154 | .spawn(|result| { 155 | println!("Set priority result: {:?}", result); 156 | assert!(result.is_ok()); 157 | }) 158 | .unwrap(); 159 | 160 | let thread2 = ThreadBuilder::default() 161 | .name("MyThread") 162 | .priority(ThreadPriority::Max) 163 | .spawn_careless(|| { 164 | println!("We don't care about the priority result."); 165 | }) 166 | .unwrap(); 167 | 168 | thread1.join().unwrap(); 169 | thread2.join().unwrap(); 170 | } 171 | 172 | pub fn start_one_thread_with_move() { 173 | let x = 100; 174 | 175 | let handle = thread::spawn(move || { 176 | println!("Hello from a thread with move, x={}!", x); 177 | }); 178 | 179 | handle.join().unwrap(); 180 | 181 | let handle = thread::spawn(move || { 182 | println!("Hello from a thread with move again, x={}!", x); 183 | }); 184 | handle.join().unwrap(); 185 | 186 | let handle = thread::spawn(|| { 187 | println!("Hello from a thread without move"); 188 | }); 189 | handle.join().unwrap(); 190 | } 191 | 192 | // pub fn start_one_thread_with_move2() { 193 | // let x = vec![1, 2, 3]; 194 | 195 | // let handle = thread::spawn(move || { 196 | // println!("Hello from a thread with move, x={:?}!", x); 197 | // }); 198 | 199 | // handle.join().unwrap(); 200 | 201 | // let handle = thread::spawn(move|| { 202 | // println!("Hello from a thread with move again, x={:?}!", x); 203 | // }); 204 | // handle.join().unwrap(); 205 | 206 | // let handle = thread::spawn(|| { 207 | // println!("Hello from a thread without move"); 208 | // }); 209 | // handle.join().unwrap(); 210 | 211 | // } 212 | 213 | pub fn start_threads_with_threadlocal() { 214 | thread_local!(static COUNTER: RefCell = RefCell::new(1)); 215 | 216 | COUNTER.with(|c| { 217 | *c.borrow_mut() = 2; 218 | }); 219 | 220 | let handle1 = thread::spawn(move || { 221 | COUNTER.with(|c| { 222 | *c.borrow_mut() = 3; 223 | }); 224 | 225 | COUNTER.with(|c| { 226 | println!("Hello from a thread7, c={}!", *c.borrow()); 227 | }); 228 | }); 229 | 230 | let handle2 = thread::spawn(move || { 231 | COUNTER.with(|c| { 232 | *c.borrow_mut() = 4; 233 | }); 234 | 235 | COUNTER.with(|c| { 236 | println!("Hello from a thread8, c={}!", *c.borrow()); 237 | }); 238 | }); 239 | 240 | handle1.join().unwrap(); 241 | handle2.join().unwrap(); 242 | 243 | COUNTER.with(|c| { 244 | println!("Hello from main, c={}!", *c.borrow()); 245 | }); 246 | } 247 | 248 | pub fn thread_park() { 249 | let handle = thread::spawn(|| { 250 | thread::park(); 251 | println!("Hello from a park thread!"); 252 | }); 253 | 254 | thread::sleep(Duration::from_millis(1000)); 255 | 256 | handle.thread().unpark(); 257 | 258 | handle.join().unwrap(); 259 | } 260 | 261 | pub fn thread_park2() { 262 | let handle = thread::spawn(|| { 263 | thread::sleep(Duration::from_millis(1000)); 264 | thread::park(); 265 | println!("Hello from a park thread in case of unpark first!"); 266 | }); 267 | 268 | handle.thread().unpark(); 269 | 270 | handle.join().unwrap(); 271 | } 272 | 273 | pub fn thread_park_timeout() { 274 | let handle = thread::spawn(|| { 275 | thread::park_timeout(Duration::from_millis(1000)); 276 | println!("Hello from a park_timeout thread!"); 277 | }); 278 | handle.join().unwrap(); 279 | } 280 | 281 | // pub fn wrong_start_threads_without_scoped() { 282 | // let mut a = vec![1, 2, 3]; 283 | // let mut x = 0; 284 | 285 | // thread::spawn(move || { 286 | // println!("hello from the first scoped thread"); 287 | // dbg!(&a); 288 | // }); 289 | // thread::spawn(move || { 290 | // println!("hello from the second scoped thread"); 291 | // x += a[0] + a[2]; 292 | // }); 293 | // println!("hello from the main thread"); 294 | 295 | // // After the scope, we can modify and access our variables again: 296 | // a.push(4); 297 | // assert_eq!(x, a.len()); 298 | // } 299 | 300 | pub fn start_scoped_threads() { 301 | let mut a = vec![1, 2, 3]; 302 | let mut x = 0; 303 | 304 | thread::scope(|s| { 305 | s.spawn(|| { 306 | println!("hello from the first scoped thread"); 307 | dbg!(&a); 308 | }); 309 | s.spawn(|| { 310 | println!("hello from the second scoped thread"); 311 | x += a[0] + a[2]; 312 | }); 313 | println!("hello from the main thread"); 314 | }); 315 | 316 | // After the scope, we can modify and access our variables again: 317 | a.push(4); 318 | assert_eq!(x, a.len()); 319 | } 320 | 321 | pub fn crossbeam_scope() { 322 | let mut a = vec![1, 2, 3]; 323 | let mut x = 0; 324 | 325 | crossbeam_thread::scope(|s| { 326 | s.spawn(|_| { 327 | println!("hello from the first crossbeam scoped thread"); 328 | dbg!(&a); 329 | }); 330 | s.spawn(|_| { 331 | println!("hello from the second crossbeam scoped thread"); 332 | x += a[0] + a[2]; 333 | }); 334 | println!("hello from the main thread"); 335 | }) 336 | .unwrap(); 337 | 338 | // After the scope, we can modify and access our variables again: 339 | a.push(4); 340 | assert_eq!(x, a.len()); 341 | } 342 | 343 | pub fn rayon_scope() { 344 | let mut a = vec![1, 2, 3]; 345 | let mut x = 0; 346 | 347 | rayon::scope(|s| { 348 | s.spawn(|_| { 349 | println!("hello from the first rayon scoped thread"); 350 | dbg!(&a); 351 | }); 352 | s.spawn(|_| { 353 | println!("hello from the second rayon scoped thread"); 354 | x += a[0] + a[2]; 355 | }); 356 | println!("hello from the main thread"); 357 | }); 358 | 359 | // After the scope, we can modify and access our variables again: 360 | a.push(4); 361 | assert_eq!(x, a.len()); 362 | } 363 | 364 | // pub fn wrong_send() { 365 | // let counter = Rc::new(42); 366 | 367 | // let (sender, receiver) = channel(); 368 | 369 | // let _t = thread::spawn(move || { 370 | // sender.send(counter).unwrap(); 371 | // }); 372 | 373 | // let value = receiver.recv().unwrap(); 374 | 375 | // println!("received from the main thread: {}", value); 376 | // } 377 | 378 | pub fn send_wrapper() { 379 | let wrapped_value = SendWrapper::new(Rc::new(42)); 380 | 381 | let (sender, receiver) = channel(); 382 | 383 | let _t = thread::spawn(move || { 384 | sender.send(wrapped_value).unwrap(); 385 | }); 386 | 387 | let wrapped_value = receiver.recv().unwrap(); 388 | 389 | let value = wrapped_value.deref(); 390 | println!("received from the main thread: {}", value); 391 | } 392 | 393 | pub fn print_thread_amount() { 394 | let mut handles = vec![]; 395 | 396 | for _ in 1..=10 { 397 | let amount = thread_amount(); 398 | 399 | let handle = thread::spawn(move || { 400 | thread::sleep(Duration::from_millis(1000)); 401 | if !amount.is_none() { 402 | println!("thread amount: {}", amount.unwrap()); 403 | } 404 | }); 405 | 406 | handles.push(handle); 407 | } 408 | 409 | for handle in handles { 410 | handle.join().unwrap(); 411 | } 412 | } 413 | 414 | pub fn control_thread() { 415 | let (flag, control) = make_pair(); 416 | let handle = thread::spawn(move || { 417 | while flag.alive() { 418 | thread::sleep(Duration::from_millis(100)); 419 | println!("I'm alive!"); 420 | } 421 | }); 422 | 423 | thread::sleep(Duration::from_millis(100)); 424 | assert_eq!(control.is_done(), false); 425 | control.stop(); // Also you can `control.interrupt()` it 426 | handle.join().unwrap(); 427 | 428 | assert_eq!(control.is_interrupted(), false); 429 | assert_eq!(control.is_done(), true); 430 | 431 | println!("This thread is stopped") 432 | } 433 | 434 | #[cfg(not(target_os = "macos"))] 435 | pub fn use_affinity() { 436 | // Select every second core 437 | let cores: Vec = (0..get_core_num()).step_by(2).collect(); 438 | println!("Binding thread to cores : {:?}", &cores); 439 | 440 | affinity::set_thread_affinity(&cores).unwrap(); 441 | println!( 442 | "Current thread affinity : {:?}", 443 | affinity::get_thread_affinity().unwrap() 444 | ); 445 | } 446 | fn foo() { 447 | println!("foo"); 448 | } 449 | pub fn go_thread() { 450 | let counter = Arc::new(AtomicI64::new(0)); 451 | let counter_cloned = counter.clone(); 452 | 453 | // Spawn a thread that captures values by move. 454 | go! { 455 | for _ in 0..100 { 456 | counter_cloned.fetch_add(1, Ordering::SeqCst); 457 | } 458 | } 459 | 460 | go!(foo()); 461 | 462 | // Join the most recent thread spawned by `go_spawn` that has not yet been joined. 463 | assert!(join!().is_ok()); 464 | assert_eq!(counter.load(Ordering::SeqCst), 100); 465 | } 466 | 467 | pub fn park_thread() { 468 | let p = Parker::new(); 469 | let u = p.unparker(); 470 | 471 | // Notify the parker. 472 | u.unpark(); 473 | 474 | // Wakes up immediately because the parker is notified. 475 | p.park(); 476 | 477 | thread::spawn(move || { 478 | thread::sleep(Duration::from_millis(500)); 479 | u.unpark(); 480 | }); 481 | 482 | // Wakes up when `u.unpark()` notifies and then goes back into unnotified state. 483 | p.park(); 484 | 485 | println!("park_unpark") 486 | } 487 | 488 | pub fn info() { 489 | let count = thread::available_parallelism().unwrap().get(); 490 | println!("available_parallelism: {}", count); 491 | 492 | if let Some(count) = num_threads::num_threads() { 493 | println!("num_threads: {}", count); 494 | } else { 495 | println!("num_threads: not supported"); 496 | } 497 | 498 | let count = thread_amount::thread_amount(); 499 | if !count.is_none() { 500 | println!("thread_amount: {}", count.unwrap()); 501 | } 502 | 503 | let count = num_cpus::get(); 504 | println!("num_cpus: {}", count); 505 | } 506 | 507 | pub fn scopeguard_defer() { 508 | defer! { 509 | println!("scopeguard: Called at return or panic"); 510 | } 511 | println!("scopeguard: Called first before panic"); 512 | // panic!(); 513 | println!("scopeguard: Called first after panic"); 514 | } 515 | 516 | 517 | 518 | 519 | macro_rules! join_all { 520 | ($($x:ident),*) => { 521 | $($x.join().unwrap();)* 522 | } 523 | } 524 | 525 | 526 | pub fn join_all_example() { 527 | let handle1 = thread::spawn(|| { 528 | println!("Hello from a thread1!"); 529 | }); 530 | 531 | let handle2 = thread::spawn(|| { 532 | println!("Hello from a thread2!"); 533 | }); 534 | 535 | join_all!(handle1,handle2); 536 | } -------------------------------------------------------------------------------- /timer_examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "timer_examples" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | async-io = "2.1.0" 10 | chrono = "0.4.22" 11 | futures-lite = "2.0.0" 12 | futures-timer = "3.0.2" 13 | safina-timer = "0.1.11" 14 | smol = "1.2.5" 15 | ticker = "0.1.1" 16 | timer = "0.2.0" 17 | -------------------------------------------------------------------------------- /timer_examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod timers; 2 | pub mod tickers; 3 | 4 | pub use timers::*; 5 | pub use tickers::*; 6 | -------------------------------------------------------------------------------- /timer_examples/src/main.rs: -------------------------------------------------------------------------------- 1 | use timer_examples::*; 2 | 3 | fn main() { 4 | timer_schedule_with_delay(); 5 | timer_schedule_with_date(); 6 | timer_repeat(); 7 | 8 | safina_timer_example(); 9 | 10 | futures_timer_example(); 11 | 12 | async_io_timer_example(); 13 | async_io_interval(); 14 | } 15 | -------------------------------------------------------------------------------- /timer_examples/src/tickers.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | use ticker::Ticker; 3 | 4 | pub fn ticker_example() { 5 | let ticker = Ticker::new(0..10, Duration::from_secs(1)); 6 | for i in ticker { 7 | println!("{:?}", i) 8 | } 9 | } 10 | 11 | pub fn async_io_interval() { 12 | use async_io::Timer; 13 | use futures_lite::StreamExt; 14 | 15 | let mut count = 0; 16 | 17 | smol::block_on(async { 18 | let mut tick = Timer::interval(Duration::from_secs(1)); 19 | 20 | while let Some(_) = tick.next().await { 21 | println!("第{}秒", count); 22 | count += 1; 23 | 24 | if count >= 10 { 25 | break; 26 | } 27 | } 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /timer_examples/src/timers.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Add; 2 | use std::sync::mpsc::channel; 3 | use std::sync::Arc; 4 | use std::sync::Mutex; 5 | use std::thread; 6 | 7 | use chrono::{self, Local}; 8 | use timer; 9 | 10 | pub fn timer_schedule_with_delay() { 11 | let timer = timer::Timer::new(); 12 | let (tx, rx) = channel(); 13 | 14 | let _guard = timer.schedule_with_delay(chrono::Duration::seconds(3), move || { 15 | // This closure is executed on the scheduler thread, 16 | // so we want to move it away asap. 17 | 18 | let _ignored = tx.send(()); // Avoid unwrapping here. 19 | }); 20 | 21 | rx.recv().unwrap(); 22 | println!("This code has been executed after 3 seconds"); 23 | } 24 | 25 | pub fn timer_schedule_with_date() { 26 | let timer = timer::Timer::new(); 27 | let (tx, rx) = channel(); 28 | 29 | let _guard = 30 | timer.schedule_with_date(Local::now().add(chrono::Duration::seconds(1)), move || { 31 | // This closure is executed on the scheduler thread, 32 | // so we want to move it away asap. 33 | 34 | let _ignored = tx.send(()); // Avoid unwrapping here. 35 | }); 36 | 37 | rx.recv().unwrap(); 38 | println!("This code has been executed after 1 seconds"); 39 | } 40 | 41 | pub fn timer_repeat() { 42 | let timer = timer::Timer::new(); 43 | // Number of times the callback has been called. 44 | let count = Arc::new(Mutex::new(0)); 45 | 46 | // Start repeating. Each callback increases `count`. 47 | let guard = { 48 | let count = count.clone(); 49 | timer.schedule_repeating(chrono::Duration::milliseconds(5), move || { 50 | *count.lock().unwrap() += 1; 51 | }) 52 | }; 53 | 54 | // Sleep one second. The callback should be called ~200 times. 55 | thread::sleep(std::time::Duration::new(1, 0)); 56 | let count_result = *count.lock().unwrap(); 57 | assert!( 58 | 190 <= count_result && count_result <= 210, 59 | "The timer was called {} times", 60 | count_result 61 | ); 62 | 63 | // Now drop the guard. This should stop the timer. 64 | drop(guard); 65 | thread::sleep(std::time::Duration::new(0, 100)); 66 | 67 | // Let's check that the count stops increasing. 68 | let count_start = *count.lock().unwrap(); 69 | thread::sleep(std::time::Duration::new(1, 0)); 70 | let count_stop = *count.lock().unwrap(); 71 | assert_eq!(count_start, count_stop); 72 | } 73 | 74 | pub fn safina_timer_example() { 75 | smol::block_on(async { 76 | safina_timer::start_timer_thread(); 77 | let duration = std::time::Duration::from_secs(1); 78 | safina_timer::sleep_for(duration).await; 79 | }); 80 | 81 | smol::block_on(async { 82 | safina_timer::start_timer_thread(); 83 | let deadline = std::time::Instant::now() + std::time::Duration::from_secs(1); 84 | safina_timer::sleep_until(deadline).await; 85 | }); 86 | } 87 | 88 | pub fn futures_timer_example() { 89 | use futures_timer::Delay; 90 | use std::time::Duration; 91 | 92 | smol::block_on(async { 93 | for _ in 0..5 { 94 | Delay::new(Duration::from_secs(1)).await; 95 | println!("重复定时任务触发!"); 96 | } 97 | }); 98 | } 99 | 100 | pub fn async_io_timer_example() { 101 | use async_io::Timer; 102 | use std::time::Duration; 103 | 104 | let timer = Timer::after(Duration::from_secs(1)); 105 | 106 | smol::block_on(async { 107 | timer.await; 108 | println!("一秒过去了"); 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /tokio_examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tokio_examples" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | tokio = { version = "1.21.2", features = ["full"] } 10 | tokio-rayon = "2.1.0" 11 | -------------------------------------------------------------------------------- /tokio_examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod primitives; 2 | 3 | pub use primitives::*; 4 | 5 | use std::process::Stdio; 6 | 7 | use tokio; 8 | use tokio::process::Command; 9 | use tokio::io::{BufReader, AsyncBufReadExt}; 10 | 11 | pub fn process() { 12 | let rt = tokio::runtime::Runtime::new().unwrap(); 13 | 14 | let _: Result<(), Box> = rt.block_on(async { 15 | let mut child = Command::new("echo") 16 | .arg("hello") 17 | .arg("world") 18 | .spawn() 19 | .expect("failed to spawn"); 20 | 21 | // Await until the command completes 22 | let status = child.wait().await?; 23 | println!("the command exited with: {}", status); 24 | 25 | Ok(()) 26 | }); 27 | } 28 | 29 | pub fn process2() { 30 | let rt = tokio::runtime::Runtime::new().unwrap(); 31 | 32 | let _: Result<(), Box> = rt.block_on(async { 33 | let mut cmd = Command::new("cat"); 34 | cmd.arg("Cargo.toml"); 35 | 36 | // Specify that we want the command's standard output piped back to us. 37 | // By default, standard input/output/error will be inherited from the 38 | // current process (for example, this means that standard input will 39 | // come from the keyboard and standard output/error will go directly to 40 | // the terminal if this process is invoked from the command line). 41 | cmd.stdout(Stdio::piped()); 42 | 43 | let mut child = cmd.spawn().expect("failed to spawn command"); 44 | 45 | let stdout = child 46 | .stdout 47 | .take() 48 | .expect("child did not have a handle to stdout"); 49 | 50 | let mut reader = BufReader::new(stdout).lines(); 51 | 52 | // Ensure the child process is spawned in the runtime so it can 53 | // make progress on its own while we await for any output. 54 | tokio::spawn(async move { 55 | let status = child 56 | .wait() 57 | .await 58 | .expect("child process encountered an error"); 59 | 60 | println!("child status was: {}", status); 61 | }); 62 | 63 | while let Some(line) = reader.next_line().await? { 64 | println!("Line: {}", line); 65 | } 66 | 67 | Ok(()) 68 | }); 69 | 70 | 71 | } 72 | 73 | 74 | pub fn oneshot() { 75 | let rt = tokio::runtime::Runtime::new().unwrap(); 76 | 77 | let _: Result<(), Box> = rt.block_on(async { 78 | let (tx, rx) = tokio::sync::oneshot::channel::(); 79 | 80 | tokio::spawn(async move { 81 | tx.send("hello".to_string()).unwrap(); 82 | }); 83 | 84 | let msg = rx.await?; 85 | println!("got = {}", msg); 86 | 87 | Ok(()) 88 | }); 89 | } 90 | 91 | pub fn async_with_oneshot() { 92 | let rt = tokio::runtime::Runtime::new().unwrap(); 93 | 94 | async fn some_computation() -> String { 95 | "the result of the computation".to_string() 96 | } 97 | 98 | let _: Result<(), Box> = rt.block_on(async { 99 | let join_handle = tokio::spawn(async move { 100 | some_computation().await 101 | }); 102 | 103 | // Do other work while the computation is happening in the background 104 | 105 | // Wait for the computation result 106 | let res = join_handle.await?; 107 | println!("result = {}", res); 108 | 109 | Ok(()) 110 | }); 111 | } 112 | 113 | pub fn mpsc_example() { 114 | async fn some_computation(input: u32) -> String { 115 | format!("the result of computation {}", input) 116 | } 117 | 118 | 119 | let rt = tokio::runtime::Runtime::new().unwrap(); 120 | 121 | let _: Result<(), Box> = rt.block_on(async { 122 | let (tx, mut rx) = tokio::sync::mpsc::channel::(10); 123 | 124 | tokio::spawn(async move { 125 | for i in 0..10 { 126 | let res = some_computation(i).await; 127 | tx.send(res).await.unwrap(); 128 | } 129 | }); 130 | 131 | while let Some(res) = rx.recv().await { 132 | println!("got = {}", res); 133 | } 134 | 135 | Ok(()) 136 | }); 137 | } 138 | 139 | pub fn broadcast_example() { 140 | let rt = tokio::runtime::Runtime::new().unwrap(); 141 | 142 | let _: Result<(), Box> = rt.block_on(async { 143 | let (tx, mut rx1) = tokio::sync::broadcast::channel::(10); 144 | let mut rx2 = tx.subscribe(); 145 | 146 | tokio::spawn(async move { 147 | tx.send("hello".to_string()).unwrap(); 148 | tx.send("world".to_string()).unwrap(); 149 | }); 150 | 151 | println!("rx1 = {:?}", rx1.recv().await); 152 | println!("rx2 = {:?}", rx2.recv().await); 153 | println!("rx2 = {:?}", rx2.recv().await); 154 | 155 | Ok(()) 156 | }); 157 | 158 | } 159 | 160 | pub fn watch_example() { 161 | let rt = tokio::runtime::Runtime::new().unwrap(); 162 | 163 | let _: Result<(), Box> = rt.block_on(async { 164 | let (tx, rx1) = tokio::sync::watch::channel::("hello".to_string()); 165 | let mut rx2 = tx.subscribe(); 166 | 167 | tokio::spawn(async move { 168 | tx.send("world".to_string()).unwrap(); 169 | }); 170 | 171 | println!("rx1 = {:?}", *rx1.borrow()); 172 | println!("rx2 = {:?}", *rx2.borrow()); 173 | println!("rx2 = {:?}", rx2.changed().await); 174 | 175 | Ok(()) 176 | }); 177 | 178 | } 179 | 180 | /// 实现fib 181 | pub fn fib(n: usize) -> usize { 182 | if n == 0 || n == 1 { 183 | return n; 184 | } 185 | 186 | return fib(n-1) + fib(n-2); 187 | } 188 | 189 | pub fn tokio_rayon_example() { 190 | let rt = tokio::runtime::Runtime::new().unwrap(); 191 | 192 | rt.block_on(async { 193 | let nft = tokio_rayon::spawn(|| { 194 | fib(20) 195 | }).await; 196 | 197 | assert_eq!(nft, 6765); 198 | }) 199 | 200 | } -------------------------------------------------------------------------------- /tokio_examples/src/main.rs: -------------------------------------------------------------------------------- 1 | use tokio_examples::*; 2 | 3 | fn main() { 4 | process(); 5 | process2(); 6 | 7 | oneshot(); 8 | async_with_oneshot(); 9 | mpsc_example(); 10 | broadcast_example(); 11 | watch_example(); 12 | 13 | barrier_example(); 14 | mutex_example(); 15 | rwlock_example(); 16 | semaphore_example(); 17 | semaphore_example2(); 18 | notify_example(); 19 | notify_example2(); 20 | 21 | tokio_rayon_example(); 22 | } 23 | -------------------------------------------------------------------------------- /tokio_examples/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use tokio::sync::Barrier; 3 | use tokio::sync::Mutex; 4 | use tokio::sync::RwLock; 5 | 6 | use tokio::sync::Notify; 7 | use tokio::sync::{Semaphore, TryAcquireError}; 8 | 9 | pub fn barrier_example() { 10 | let rt = tokio::runtime::Runtime::new().unwrap(); 11 | 12 | rt.block_on(async { 13 | let mut handles = Vec::with_capacity(10); 14 | let barrier = Arc::new(Barrier::new(10)); 15 | for _ in 0..10 { 16 | let c = barrier.clone(); 17 | // The same messages will be printed together. 18 | // You will NOT see any interleaving. 19 | handles.push(tokio::spawn(async move { 20 | println!("before wait"); 21 | let wait_result = c.wait().await; 22 | println!("after wait"); 23 | wait_result 24 | })); 25 | } 26 | 27 | // Will not resolve until all "after wait" messages have been printed 28 | let mut num_leaders = 0; 29 | for handle in handles { 30 | let wait_result = handle.await.unwrap(); 31 | if wait_result.is_leader() { 32 | num_leaders += 1; 33 | } 34 | } 35 | 36 | // Exactly one barrier will resolve as the "leader" 37 | assert_eq!(num_leaders, 1); 38 | }); 39 | } 40 | 41 | pub fn mutex_example() { 42 | let rt = tokio::runtime::Runtime::new().unwrap(); 43 | 44 | rt.block_on(async { 45 | let data1 = Arc::new(Mutex::new(0)); 46 | let data2 = Arc::clone(&data1); 47 | 48 | tokio::spawn(async move { 49 | let mut lock = data2.lock().await; 50 | *lock += 1; 51 | }); 52 | 53 | let mut lock = data1.lock().await; 54 | *lock += 1; 55 | }); 56 | } 57 | 58 | pub fn rwlock_example() { 59 | let rt = tokio::runtime::Runtime::new().unwrap(); 60 | 61 | rt.block_on(async { 62 | let lock = RwLock::new(5); 63 | 64 | // many reader locks can be held at once 65 | { 66 | let r1 = lock.read().await; 67 | let r2 = lock.read().await; 68 | assert_eq!(*r1, 5); 69 | assert_eq!(*r2, 5); 70 | } // read locks are dropped at this point 71 | 72 | // only one write lock may be held, however 73 | { 74 | let mut w = lock.write().await; 75 | *w += 1; 76 | assert_eq!(*w, 6); 77 | } // write lock is dropped here 78 | }); 79 | } 80 | 81 | pub fn semaphore_example() { 82 | let rt = tokio::runtime::Runtime::new().unwrap(); 83 | 84 | rt.block_on(async { 85 | let semaphore = Semaphore::new(3); 86 | 87 | let _a_permit = semaphore.acquire().await.unwrap(); 88 | let _two_permits = semaphore.acquire_many(2).await.unwrap(); 89 | 90 | assert_eq!(semaphore.available_permits(), 0); 91 | 92 | let permit_attempt = semaphore.try_acquire(); 93 | assert_eq!(permit_attempt.err(), Some(TryAcquireError::NoPermits)); 94 | }); 95 | } 96 | 97 | pub fn semaphore_example2() { 98 | let rt = tokio::runtime::Runtime::new().unwrap(); 99 | 100 | rt.block_on(async { 101 | let semaphore = Arc::new(Semaphore::new(3)); 102 | let mut join_handles = Vec::new(); 103 | 104 | for _ in 0..5 { 105 | let permit = semaphore.clone().acquire_owned().await.unwrap(); 106 | join_handles.push(tokio::spawn(async move { 107 | // perform task... 108 | // explicitly own `permit` in the task 109 | drop(permit); 110 | })); 111 | } 112 | 113 | for handle in join_handles { 114 | handle.await.unwrap(); 115 | } 116 | }); 117 | } 118 | 119 | pub fn notify_example() { 120 | let rt = tokio::runtime::Runtime::new().unwrap(); 121 | 122 | rt.block_on(async { 123 | let notify = Arc::new(Notify::new()); 124 | let notify2 = notify.clone(); 125 | 126 | let handle = tokio::spawn(async move { 127 | notify2.notified().await; 128 | println!("received notification"); 129 | }); 130 | 131 | println!("sending notification"); 132 | notify.notify_one(); 133 | 134 | // Wait for task to receive notification. 135 | handle.await.unwrap(); 136 | }); 137 | } 138 | 139 | pub fn notify_example2() { 140 | let rt = tokio::runtime::Runtime::new().unwrap(); 141 | 142 | rt.block_on(async { 143 | let notify = Arc::new(Notify::new()); 144 | let notify2 = notify.clone(); 145 | 146 | let notified1 = notify.notified(); 147 | let notified2 = notify.notified(); 148 | 149 | let _handle = tokio::spawn(async move { 150 | println!("sending notifications"); 151 | notify2.notify_waiters(); 152 | }); 153 | 154 | notified1.await; 155 | notified2.await; 156 | println!("received notifications"); 157 | }); 158 | } 159 | --------------------------------------------------------------------------------