├── .gitignore ├── templates └── .gitignore ├── content ├── _index.md ├── hello-world.md ├── en │ └── understanding-atomics.md └── entendendo-atomicos.md ├── static ├── favicon.ico ├── apple-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon-96x96.png ├── ms-icon-70x70.png ├── apple-icon-57x57.png ├── apple-icon-60x60.png ├── apple-icon-72x72.png ├── apple-icon-76x76.png ├── imgs │ └── common │ │ ├── logo.png │ │ └── base_og_image.png ├── ms-icon-144x144.png ├── ms-icon-150x150.png ├── ms-icon-310x310.png ├── android-icon-36x36.png ├── android-icon-48x48.png ├── android-icon-72x72.png ├── android-icon-96x96.png ├── apple-icon-114x114.png ├── apple-icon-120x120.png ├── apple-icon-144x144.png ├── apple-icon-152x152.png ├── apple-icon-180x180.png ├── android-icon-144x144.png ├── android-icon-192x192.png ├── apple-icon-precomposed.png ├── browserconfig.xml └── manifest.json ├── .gitmodules ├── README.md ├── .travis.yml └── config.toml /.gitignore: -------------------------------------------------------------------------------- 1 | public -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /content/_index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | paginate_by = 5 3 | +++ -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon.png -------------------------------------------------------------------------------- /static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/favicon-96x96.png -------------------------------------------------------------------------------- /static/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-70x70.png -------------------------------------------------------------------------------- /static/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-57x57.png -------------------------------------------------------------------------------- /static/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-60x60.png -------------------------------------------------------------------------------- /static/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-72x72.png -------------------------------------------------------------------------------- /static/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-76x76.png -------------------------------------------------------------------------------- /static/imgs/common/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/imgs/common/logo.png -------------------------------------------------------------------------------- /static/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-144x144.png -------------------------------------------------------------------------------- /static/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-150x150.png -------------------------------------------------------------------------------- /static/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/ms-icon-310x310.png -------------------------------------------------------------------------------- /static/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-36x36.png -------------------------------------------------------------------------------- /static/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-48x48.png -------------------------------------------------------------------------------- /static/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-72x72.png -------------------------------------------------------------------------------- /static/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-96x96.png -------------------------------------------------------------------------------- /static/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-114x114.png -------------------------------------------------------------------------------- /static/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-120x120.png -------------------------------------------------------------------------------- /static/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-144x144.png -------------------------------------------------------------------------------- /static/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-152x152.png -------------------------------------------------------------------------------- /static/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-180x180.png -------------------------------------------------------------------------------- /static/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-144x144.png -------------------------------------------------------------------------------- /static/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/android-icon-192x192.png -------------------------------------------------------------------------------- /static/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/apple-icon-precomposed.png -------------------------------------------------------------------------------- /static/imgs/common/base_og_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-br/blog/HEAD/static/imgs/common/base_og_image.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "themes/dinkleberg"] 2 | path = themes/dinkleberg 3 | url = https://github.com/rust-br/dinkleberg.git 4 | -------------------------------------------------------------------------------- /static/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RustBR Blog 2 | Repositório oficial do Blog da Comudidade Rust BR :D 3 | 4 | ## Contribuindo 5 | Se deseja contribuir como o layout, o tema utilizado foi desenvolvido pela própria comunidade e pode ser acessado [clicando aqui](https://github.com/rust-br/dinkleberg) 6 | 7 | Caso deseje escrever uma publicação sugerimos que leia o [essa postagem](https://rust-br.github.io/blog/hello-world/) no nosso blog. 8 | -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - curl -s -L https://github.com/Keats/gutenberg/releases/download/v0.3.1/gutenberg-v0.3.1-x86_64-unknown-linux-gnu.tar.gz | sudo tar xvzf - -C /usr/local/bin 3 | script: 4 | - gutenberg build 5 | deploy: 6 | provider: pages 7 | skip-cleanup: true 8 | github-token: 9 | secure: Oufj4oNvtFr98ny/dpoar4+ObCTjYGbh2smZ5EUMz4dL9qodCsg2+IIbcMwwWGGydAH5XjG4syEzeyxsquRlD0B0E75NTPzKUyqAZ8hom0wnyPDuwPcGOxOgYvPW7Dxo9kJO6kreyXZKmGg9rMOyEGKGyYcSJqk5EXHkFpuc79Jx+99A3zvarB+QAUvAADevTNYb5nFpUV3DCV1E5X3dVy0fNv7gyBU83GzrXAxlwfFXCwbf9PIEEhxSnyzD6EPt/EgUn9RLJyazwgY1uu1VsQ5/Q4hov3EiKRYtWpjAcgvLM1O4phTngXogQg+BYwXaSvaqSwh6FwlkXar2z47sqi3ej8it99v1NawCGP3Z233OeqdISKawhFjUwh1p6iuDy1hma1qGwLgCh0aapfgi09Obbp1XqhJGD2U0CCDIvxOKk+Hy0om1w74PpD2XJWv3vWddGBwLCz/F7gtuaIZCbohWaozW21gPvNGwCPH1oIvE+gH3GPac7/jzz2MCaAGsJZGgeFhY9YWIgET+g7QtlHeDLFlvQfNNWgnbbROHQkJg1I0P36Nbec5T6kQcMyAIaHGEBW/wNtxrdYnreT038do7LF4er8Oz9KrIf9vKNDFF7UV/yKbosff6rJZapXipleX/icjgMsNL//Gt5W2scpk02p6x3FvL1zy5Yn4GTa0= 10 | keep-history: true 11 | local-dir: public 12 | on: 13 | branch: master 14 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | base_url = "https://rust-br.github.io/blog" 2 | 3 | # RSS 4 | title = "Rust Brasil: Dividindo conhecimento sobre a linguagem Rust" 5 | description = "Um blog com conteúdo focado no público brasileiro escrito, grande parte, em português sobre a linguagem de programção Rust" 6 | default_language = "pt" 7 | 8 | theme = "dinkleberg" 9 | compile_sass = true 10 | 11 | highlight_code = true 12 | highlight_theme = "gruvbox-dark" 13 | 14 | generate_tags_pages = true 15 | generate_categories_pages = true 16 | 17 | [extra] 18 | blog_logo = "/imgs/common/logo.png" 19 | blog_title="rust::brasil::Blog" 20 | label_tags = "Tags" 21 | label_tag = "Tag" 22 | label_categories = "Categorias" 23 | label_category = "Categoria" 24 | label_relative_posts = "Postagens Relacionadas" 25 | label_next = "Próxima" 26 | label_previous = "Anterior" 27 | label_page = "Página" 28 | label_of = "de" 29 | 30 | og_image="https://rust-br.github.io/blog/imgs/common/base_og_image.png" 31 | og_alt_image="Rust Brasil Blog" 32 | og_site_name="Rust Brasil Blog" 33 | keywords="Rust, Lang, Language, Linguagem de Programação, Desenvolvimento, Brazil, Brasil" 34 | 35 | educational_use="knowledge share" 36 | copyright_year="2018" 37 | 38 | sidebar = [ 39 | {name = "Social", urls=[ 40 | {name="Telegram", url="https://t.me/rustlangbr"}, 41 | {name="Github", url="https://github.com/rust-br"}, 42 | ]}, 43 | {name = "Divida Conhecimento!", urls=[ 44 | {name="Contribuir!", url="https://rust-br.github.io/blog/hello-world"} 45 | ]} 46 | ] 47 | -------------------------------------------------------------------------------- /content/hello-world.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "println!(\"Hello World!\")" 3 | description = "Blog, como nasceu, onde está, como vive. Hoje no Rust Brasil" 4 | date=2018-05-28 5 | category = "Apresentação" 6 | tags = ["amigavel a iniciantes", "introdução", "gutenberg"] 7 | 8 | [extra] 9 | author="Guilherme Diego" 10 | +++ 11 | 12 | Olá, me chamo Guilherme Diego e sou muitas coisas nessa vida e uma delas é ser entusiasta de coisas que em meu ponto de vista são boas, e esse foi o meu caso com RUST. Desde que comecei minha jornada pelo maravilhoso mundo de rust, eu tenho recebido ajuda da incrível comunidade que é a Rust Brasil pelo [telegram](https://t.me/rustlangbr), e já não é recente o assunto de: *"Devíamos criar um blog"*. Eu sou *front-end* já fazem quase 6 anos, e me responsabilizei por erguer os templates e tomar a frente de organizar o blog junto com outras pessoas que queriam dividir conhecimentos. O que nos faz chegar ao motivo dessa postagem: Introduzir como o Blog foi feito e como contribuir para ele. 13 | 14 | ## Gutenberg (ou Dinkleberg) 15 | Quando iniciamos nossas discussões para o que usaríamos para erguer o blog estático no Github, e optamos pelo [**Gutenberg**](https://www.getgutenberg.io/), uma alternativa a grandes nomes como Hugo, Jenkyll e Cobalt, porem, escrito em Rust <3. Gutenberg tem uma mecânica muito simples, ele é composto por 4 pastas: 16 | 17 | - **content**: Onde fica as páginas 18 | - **templates**: Onde fica os *templates* a serem rendenizados 19 | - **sass**: Onde fica os estilos em `scss` 20 | - **themes** Onde fica os temas 21 | 22 | Por incrível que pareça, um tema nada mais é que um site Gutenberg sobrescrito por informações de outro site Gutenberg! Bruxaria? Talvez! Logo foi dado início a um tema do zero para o nosso Blog. Logo a primeira vez que ouvi o nome da ferramenta, eu um amante de padrinhos mágicos, já cerrei meus olhos e disse lentamente: "Dinkleberg", acabamos aderindo em `alias`, até que eu batizei o tema que escrevemos como: 23 | 24 | ![753986_1](https://user-images.githubusercontent.com/10289071/40806112-dd79ae78-64f6-11e8-8f24-63f387d5bb8f.jpg) 25 | 26 | Logo, caso sinta vontade de contribuir com o tema você pode achar ele [aqui](https://github.com/rust-br/dinkleberg). Se você deseja publicar algo irei agora explicar como publicar. 27 | 28 | ## Contribuindo 29 | Existem dois jeitos de contribuir: MANUALMENTE pelo seu computador, ou direto pelo Github. Irei mostrar ambas! 30 | 31 | ### Manualmente 32 | - Faça um fork do repositório do blog: [https://github.com/rust-br/blog](https://github.com/rust-br/blog) 33 | - Clone ele na sua maquina 34 | - Entre na pasta 35 | - `git submodule init` 36 | - `git submodule update` 37 | - Crie um arquivo na raiz do `/content` com o `slug` do seu artigo, exemplo: `borrow-checker-para-iniciantes.md` 38 | - Escreva / commit / push 39 | - Abra um pull request para o master go rust-br/blog 40 | 41 | OBS: Caso queira rodar local, instale o [gutenberg]() e rode `gutenberg --config config.toml serve` 42 | 43 | ### Pelo Github 44 | - Faça um fork do repositório do blog: [https://github.com/rust-br/blog](https://github.com/rust-br/blog) 45 | - Crie um branch 46 | - captura de tela 2018-05-31 as 17 31 54 47 | - Pelo próprio github acesse a pasta content, e clique em (Create new file / Criar novo arquivo no canto superior direito) 48 | - captura de tela 2018-05-31 as 17 32 19 49 | - Escreva seu post e commit 50 | - captura de tela 2018-05-31 as 17 32 39 51 | - abra um pull request para o master go rust-br/blog 52 | 53 | OBS: É possível editar os arquivos pelo github! Uma vez que eles estejam na pasta `/content`, basta clicar no arquivo que deseja editar e posteriormente no lápis no canto superior direito 54 | captura de tela 2018-05-31 as 17 37 05 55 | 56 | ## Boas Práticas 57 | É necessário que se siga boas práticas para que o post tenha o resultado necessário, algumas informações são obrigatórias quando criar o post! 58 | 59 | ### Cabeçalho 60 | 61 | ```markdown 62 | +++ 63 | title = "println!(\"Hello World!\")" # TITULO DO POST 64 | description = "Blog, como nasceu, onde está, como vive. Hoje no Rust Brasil" # DESCRIÇÃO DO POST 65 | date=2018-05-28 # DATA DE PUBLICAÇÃO 66 | category = "Apresentação" # Categoria da publicação 67 | tags = ["amigável a iniciantes", "introdução", "gutenberg"] # Tags relacionadas 68 | 69 | [extra] 70 | author="Guilherme Diego" # Nome do autor (mantenha o padrão entre suas postagens :D) 71 | updated_date=2018-05-29 # Data que você editou o post 72 | +++ 73 | ``` 74 | 75 | O **updated_date** é o único parâmetro NÃO OBRIGATÓRIO do header! Posts sem os requisitos serão negados. Você pode pedir ajuda a qualquer momento para encaixar seu post em uma **Categoria** e colocar as **Tags** nela, estaremos sempre dispostos a ajudar. 76 | 77 | ### Branch 78 | É recomendado que use a nomenclatura `post/nome-do-meu-post` quando for inserir um novo post no blog e `repost/nome-do-meu-post` quando for atualizar um post. Em caso de atualização de tema ou ajuste em templates ou outras coisas use a nomenclatura `fix/resumo-do-que-fez` 79 | 80 | ### Português Por Favor 81 | Somos um blog brasileiro, logo, é **OBRIGATÓRIO** que o post seja em português, caso queira postar uma versão em inglês você pode estar traduzindo e postando seu post dentro da pasta `/en/nome-do-seu-post-em-inglês`, e adicionando ele nos `relative_posts` do seu cabeçalho: 82 | 83 | ```markdown 84 | +++ 85 | relative_posts=[ 86 | {label="Postagem em Inglês", url="/en/nome-do-seu-post-em-inglês"} 87 | ] 88 | +++ 89 | ``` 90 | 91 | ## Conclusão 92 | Dividir conhecimento é uma das melhores maneiras de aprender e/ou aprimorar um conhecimento enquanto ajuda pessoas que ainda não portam o mesmo. Um blog, dentro de uma comunidade, é um passo importante para o fortalecimento e difusão de conhecimento dentro dela. Não esqueça de entrar no grupo de telegrama, opinar em posts abrindo ***issues*** no Github. Leia também os códigos de consulta, seguiremos ele dentro da comunidade e consecutivamente no blog: 93 | 94 | [https://www.rust-lang.org/pt-BR/conduct.html](https://www.rust-lang.org/pt-BR/conduct.html) 95 | 96 | Abraços e até a próxima! 97 | -------------------------------------------------------------------------------- /content/en/understanding-atomics.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Understanding Atomics" 3 | description = "Explains the basic of atomics in Rust. Comes with a bonus: spinlock implementation." 4 | date = 2018-05-30 5 | tags = ["atomics"] 6 | category = "concurrency" 7 | [extra] 8 | relative_posts = [ {label="Post em português", url="/entendendo-atomicos"} ] 9 | author = "Bruno Corrêa Zimmermann" 10 | +++ 11 | 12 | # Abstract 13 | 14 | In this post I will explain what are atomics and how to use them in rust. 15 | 16 | 17 | # "What is an 'atomic' anyway?" 18 | 19 | Atomics are data types on which operations are indivisible, 20 | or the indivisible operations by themselves. Indivisible here means that 21 | the side effects of the operations are only observable when the operation 22 | is done. Generally, machines provide read and write operations over its 23 | native integer both indivisible and divisible. 24 | 25 | If you have ever heard of "data races", divisible read and write causes them. 26 | Suppose we are on a 64-bit word machine. Threads `A`, `B` and `C` have 27 | access to address `p`. If `A` does a "divisible" write on `p` with `x`, 28 | at the same time `C` does a "divisible" read, `C` might get half of previous 29 | bits of `p` and half bits of `x`. Or a quarter of bits. Or the previous state. 30 | Or the new state. It's actualy hard to predict. If thread `A` writes 31 | "divisibily" again on `p` with `y` at the same time thread `B` writes 32 | "divisibily" `z`, the resulting value of `p` might be a mix of both states or 33 | something similar. 34 | 35 | Because the behavior might vary between different machines, programming 36 | languages such as Rust and C++ defines data races as undefined behavior. The 37 | actual behavior might not be "leaving an intermediate value", but it could 38 | be anything, from throwing an exception to setting the processor on fire. 39 | You probably noticed that the problem here are the "divisible" operations. 40 | If `A` had atomically written `x` on `p`, and `C` had atomically read from 41 | `p`, `C` would see the bits of `p` either before of `A`'s write or after the 42 | write, but not in the middle. The same apply for `A` and `B` writing 43 | atomically; the final state would be either `y` or `z`, but not anything else. 44 | 45 | There is also race condition. Race condition is similar to data race, but it 46 | can happen even with atomics. Race condition is about dependency between the 47 | order of asynchronous events, but it does not corrupt data. Race condition 48 | is what generally makes atomic data structures hard to be written. One should 49 | think carefully when writing atomic code. 50 | 51 | # Atomics in Rust 52 | 53 | Currently (rust nightly 1.28 and stable 1.26) these atomic data types were 54 | stabilized: `AtomicPtr`, `AtomicUsize`, `AtomicIsize` and `AtomicBool`. 55 | They are all located in `core::sync::atomic` (or `std::sync::atomic`). 56 | To explain, I will pick the simplest one: `AtomicBool`. 57 | 58 | ## `AtomicBool` 59 | 60 | It is very simple to create one: 61 | 62 | ```rust 63 | let atomic_bool = AtomicBool::new(true); 64 | ``` 65 | 66 | Now let's make an atomic read. But wait... uh oh... `AtomicBool::load` 67 | accepts two arguments: an immutable reference to `self` and another 68 | argument of type `Ordering`. The reference to `self` is easily understandable 69 | but what about `Ordering`? `Ordering` is a type which determinates the... 70 | the... order? Yes, the order related to other operations and other threads. 71 | Let's see the definition of `Ordering`: 72 | 73 | ```rust 74 | pub enum Ordering { 75 | Relaxed, 76 | Release, 77 | Acquire, 78 | AcqRel, 79 | SeqCst, 80 | // some variants omitted 81 | } 82 | ``` 83 | 84 | There are, roughly speaking, two kinds of CPUs related to orderings: the weak 85 | and the strong. The weak processors have naturally weak guarantees on the 86 | orderings, while the strong processors have naturally strong guarantees on the 87 | orderings. It is generally low-cost for strong-processors to perform `Acquire`, 88 | `Relase` and `AcqRel`, while they are high-cost for weak-processors. For all 89 | of them `Relaxed` is low-cost and `SeqCst` is high-cost. Examples of weak- 90 | processors are ARM-archs, and examples of strong-processors are the ones 91 | x86/x86_64-archs. 92 | 93 | The only valid variants for `load` to be called with are: `Relaxed`, `Acquire` 94 | and `SeqCst`. Don't worry, the other variants will be explained later. `Relaxed` 95 | is somewhat like "the order does not matter at all". This allows both 96 | the compiler and the CPU to reorder the operation. `SeqCst` means "sequentially 97 | consistent"; it should not be reordered at all! Everything before it happens 98 | before it, and everything after it happens after it. 99 | 100 | `Acquire` is a bit more complex. It is the "complement" of `Release`. 101 | Everything (generally `store`-like operations) that happens after the `Acquire` 102 | stays after it. But the compiler and the CPU are free to reorder anything that 103 | happens before it. It is designed to be used with `load`-like operations when 104 | acquiring locks. 105 | 106 | Let's see an example with `AtomicBool::load`: 107 | 108 | ```rust 109 | use std::sync::atomic::{ 110 | AtomicBool, 111 | Ordering::*, 112 | }; 113 | 114 | fn print_if_it_is(atomic: &AtomicBool) { 115 | if atomic.load(Acquire) { 116 | println!("It is!"); 117 | } 118 | } 119 | ``` 120 | 121 | Let's jump into the next operation: `store`. `store` accepts a reference to 122 | `self`, the new value (of type `bool`), and an `Ordering`. The valid 123 | `Ordering`s are `Relaxed`, `Release` and `SeqCst`. `Release`, as said before, 124 | is used as a pair with `Acquire`. Everything before `Release` happens before 125 | it, but the compiler and the CPU are free to reorder anything that happens 126 | after it. It is intended to be used when releasing a lock. 127 | 128 | Let's see an example: 129 | 130 | ```rust 131 | use std::sync::atomic::{ 132 | AtomicBool, 133 | Ordering::*, 134 | }; 135 | 136 | fn store_something(atomic: &AtomicBool) { 137 | atomic.store(false, Release); 138 | } 139 | ``` 140 | 141 | You may have noticed two things. If you did not notice them, do it now. First: 142 | `store` just needs an immutable reference. This means that it does not need 143 | "outer" mutability, but it has inner mutability. Second: atomics are only 144 | useful with shared references. They don't have anything like "`clone`"; to 145 | clone you can do somewhat `let copied = AtomicBool::new(src.load(Acquire));`. 146 | But this does not share the atomic. Therefore, it is a common pattern to 147 | encapsulate the atomic (or the struct which keeps the atomic) into an `Arc`. 148 | 149 | There are at least three more important operations `swap`, `compare_and_swap`, 150 | `compare_exchange_*`. Swap is pretty simple: it swaps its argument (of type 151 | `bool`) with the stored value, and returns the stored value. `Ordering` on 152 | swap accepts any of the `Ordering`s. `compare_and_swap` takes a `bool`, say, 153 | "current", another `bool`, say "new", and the `Ordering` (which can be any). 154 | `compare_and_swap` is a really important atomic operation. It compares the 155 | argument "current" with the stored value. If they are the same, the operation 156 | swaps the stored value with "new". In any case, the stored value is returned. 157 | The operation succeeds if the return value is equal to the "current" argument. 158 | 159 | There is also `compare_exchange_strong` (just `compare_exchange` in Rust), and 160 | `compare_exchange_weak` (which may fail more often). They are similar to 161 | `compare_and_swap`, except that they take two orderings: one for success, and 162 | one for failure. Also, in Rust they return a `Result`. The fact that these 163 | operations return a `Result` allows `compare_exchange_weak` to fail even if 164 | the comparison succeed. Important: success `Ordering` accepts the same 165 | `Ordering`s as a `swap`, but failure `Ordering` has to be weaker than success 166 | or equivalent, but valid for `load`. 167 | 168 | Wait! I did not explain `Ordering::AcqRel`. It is what it seems: it combines 169 | `Acquire` when loading and `Release` when storing for operations that 170 | load/store atomically. Although I explained all of these using `AtomicBool`, 171 | they are pretty much common primitive operations for all primitive atomic data 172 | types. All atomic data types in Rust have at least these operations: `load`, 173 | `store`, `swap`, `compare_and_swap`, `compare_exchange`, 174 | `compare_exchange_weak`. Enough of talk, let's act! 175 | 176 | ## Lock-free logical AND 177 | 178 | The function below receives an atomic boolean, an ordinary boolean, stores the 179 | logical AND of them and returns the previous value. 180 | 181 | ```rust 182 | use std::sync::atomic::{AtomicBool, Ordering::{*, self}}; 183 | 184 | fn lockfree_and(x: &AtomicBool, y: bool, ord: Ordering) -> bool { 185 | let mut stored = x.load(match ord { 186 | AcqRel => Acquire, 187 | Release => Relaxed, 188 | o => o, 189 | }); 190 | loop { 191 | let inner = x.compare_and_swap(stored, stored & y, ord); 192 | if inner == stored { 193 | break inner; 194 | } 195 | stored = inner; 196 | } 197 | } 198 | ``` 199 | 200 | Note that side-effects are only visible after we're done. This is, in some way, 201 | "atomic". Generally, this kind of operation is called "lock-free" because it 202 | does not use any kind of lock. Although we have a loop, we do not depend on 203 | any thread "free-ing" the resource. This is not a lock. 204 | 205 | And, well... Rust already provides us a method `AtomicBool::fetch_and`, which 206 | probably is translated into a single native instruction. I just wanted to show 207 | you that with the primitives `load` and `compare_and_swap`, the operation can 208 | be implemented via software. 209 | [Take a look here](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_and), 210 | we have other methods on `AtomicBool`, such as `nand`, `or`, and `xor`. 211 | 212 | As you may suspect, `AtomicUsize` and `AtomicIsize` have their own methods with 213 | basic arithmetic (add and sub) and bitwise. And all of them are implementable 214 | via software, but probably are implemented in such a way they are translated 215 | into a single native instruction. Although the API does not provide `mul` and 216 | `div`, it is not hard to implement them. 217 | 218 | ## A note on `AtomicPtr` 219 | 220 | `AtomicPtr` can be confusing. The methods `load` and `store` read and write 221 | the address or its content? The answer is: the address. They operate on `*mut T`. 222 | To load the contents is pretty much another operation, but it is not atomic and 223 | and it is very unsafe. 224 | 225 | ## `Send` and `Sync` 226 | 227 | You may have heard of the auto traits `Send` and `Sync`. They matter a lot in a 228 | concurrent environment. `T: Send` means `T` is safe to be sent to another 229 | thread. `T: Sync` means `&T` is safe to be shared between threads. Atomic data 230 | types implement both `Send` and `Sync`, so it is safe to share and send them 231 | among threads. 232 | 233 | 234 | ## Bonus: Implementing a spinlock 235 | 236 | ```rust 237 | pub mod spinlock { 238 | use std::{ 239 | cell::UnsafeCell, 240 | fmt, 241 | ops::{Deref, DerefMut}, 242 | sync::atomic::{ 243 | AtomicBool, 244 | Ordering::*, 245 | }, 246 | }; 247 | 248 | #[derive(Debug)] 249 | pub struct Mutex { 250 | locked: AtomicBool, 251 | inner: UnsafeCell, 252 | } 253 | 254 | #[derive(Debug, Clone, Copy)] 255 | pub struct MutexErr; 256 | 257 | pub struct MutexGuard<'a, T> 258 | where 259 | T: 'a 260 | { 261 | mutex: &'a Mutex, 262 | } 263 | 264 | impl Mutex { 265 | pub fn new(data: T) -> Self { 266 | Self { 267 | locked: AtomicBool::new(false), 268 | inner: UnsafeCell::new(data), 269 | } 270 | } 271 | 272 | pub fn try_lock<'a>(&'a self) -> Result, MutexErr> { 273 | if self.locked.swap(true, Acquire) { 274 | Err(MutexErr) 275 | } else { 276 | Ok(MutexGuard { 277 | mutex: self, 278 | }) 279 | } 280 | } 281 | 282 | pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> { 283 | loop { 284 | if let Ok(m) = self.try_lock() { 285 | break m; 286 | } 287 | } 288 | } 289 | } 290 | 291 | unsafe impl Send for Mutex 292 | where 293 | T: Send, 294 | { 295 | } 296 | 297 | unsafe impl Sync for Mutex 298 | where 299 | T: Send, 300 | { 301 | } 302 | 303 | impl Drop for Mutex { 304 | fn drop(&mut self) { 305 | unsafe { 306 | self.inner.get().drop_in_place() 307 | } 308 | } 309 | } 310 | 311 | impl<'a, T> Deref for MutexGuard<'a, T> { 312 | type Target = T; 313 | 314 | fn deref(&self) -> &T { 315 | unsafe { 316 | &*self.mutex.inner.get() 317 | } 318 | } 319 | } 320 | 321 | impl<'a, T> DerefMut for MutexGuard<'a, T> { 322 | fn deref_mut(&mut self) -> &mut T { 323 | unsafe { 324 | &mut *self.mutex.inner.get() 325 | } 326 | } 327 | } 328 | 329 | impl<'a, T> fmt::Debug for MutexGuard<'a, T> 330 | where 331 | T: fmt::Debug, 332 | { 333 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 334 | write!(fmtr, "{:?}", &**self) 335 | } 336 | } 337 | 338 | impl<'a, T> Drop for MutexGuard<'a, T> { 339 | fn drop(&mut self) { 340 | let _prev = self.mutex.locked.swap(false, Release); 341 | debug_assert!(_prev); 342 | } 343 | } 344 | 345 | } 346 | ``` 347 | -------------------------------------------------------------------------------- /content/entendendo-atomicos.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Entendendo Atômicos" 3 | description = "Explica o básico de atômicos em Rust. Vem com um bônus: implementação de spinlock." 4 | date = 2018-05-30 5 | tags = ["atômicos"] 6 | category = "concorrência" 7 | [extra] 8 | relative_posts = [ {label="English post", url="/en/understanding-atomics"} ] 9 | author = "Bruno Corrêa Zimmermann" 10 | +++ 11 | 12 | # Resumão 13 | 14 | Neste post, explicarei o que são atômicos e como usá-los em Rust. 15 | 16 | # "De qualquer forma, o que seria um 'atômico'?" 17 | 18 | Atômicos são tipos de dados com operações indivisíveis ou as próprias 19 | operações indivisíveis. Aqui, indivisível significa que os efeitos dessas 20 | operações só são observáveis quando a operação já acabou. Normalmente, as 21 | máquinas fornecem leitura e escrita tanto divisíveis quanto indivisíveis 22 | sobre os inteiros nativos. 23 | 24 | Se você já ouviu falar de "_data races_" (corrida de dados em tradução 25 | literal), saiba que leitura e escrita divisíveis causam-nas. Suponha uma 26 | máquina com palavra de 64 bits. Suponha _threads_ `A`, `B` e `C`, todas com 27 | acesso ao endereço `p`. Se `A` faz uma escrita "divisível" de `x` em `p` ao 28 | mesmo tempo em que `C` faz uma leitura "divisível", `C` pode ficar com metade 29 | dos bits anteriores de `p` e metade dos bits de `x`. Ou um quarto desses bits. 30 | Ou o estado anterior. Ou o novo estado. Na verdade, é difícil prever. Se 31 | a thread `A` escreve "divisivelmente" `y`, de novo em `p`, ao mesmo tempo em 32 | que a thread `B` escreve "divisivelmente" `z`, o resultado de `p` pode ser uma 33 | mistura de `y` e `z` ou algo similar. 34 | 35 | Pelo fato do comportamento variar em diferentes máquinas, as linguagens de 36 | programação como Rust e C++ definem _data races_ como comportamento indefinido 37 | (_undefined behavior_). O comportamento real pode não ser "deixar um estado 38 | intermediário", mas qualquer coisa, de "lançar uma exceção" até "incendiar o 39 | processador". Você provavelmente deve ter notado que o problema aqui são as 40 | operações "divisíveis". Se `A` tivesse escrito `x` em `p` atomicamente, e `C` 41 | tivesse lido de `p` também atomicamente, `C` veria os bits de `p` ou antes 42 | ou depois da escrita de `A`, mas nunca no meio. O mesmo se aplica à `A` e `B` 43 | escreverem atomicamente; o estado final seria ou `y` ou `z`, mas nada além disso. 44 | 45 | Há ainda a chamada "_race condition_" (condição de corrida). Condição de 46 | corrida é similar a _data race_, mas pode ocorrer até mesmo com atômicos. 47 | Race condition é sobre dependência da ordem de eventos assíncronos, mas 48 | não necessariamente corrompe dados. Condição de corrida é o que costuma 49 | tornar estruturas de dados atômicas difíceis de serem escritas. Você 50 | deve pensar com cuidado ao escrever código atômico. 51 | 52 | # Atômicos em Rust 53 | 54 | Atualmente (rust nightly 1.28 e stable 1.26) estes tipos de dados atômics 55 | foram estabilizados: `AtomicPtr`, `AtomicUsize`, `AtomicIsize` and 56 | `AtomicBool`. Eles se localizam em `core::sync::atomic` (ou 57 | `std::sync::atomic`). Para explicar, escolhi o mais simples: `AtomicBool`. 58 | 59 | ## `AtomicBool` 60 | 61 | É bastante simples criar um `AtomicBool`: 62 | 63 | ```rust 64 | let atomic_bool = AtomicBool::new(true); 65 | ``` 66 | 67 | Agora, vamos fazer leitura atômica! Mas espere... opa... `AtomicBool::load` 68 | (carregar) aceita dois argumentos: uma referência imutável para `self` e um 69 | argumento do tipo `Ordering`. A referência para `self` acredito ser fácil de 70 | entender, mas e o `Ordering`? `Ordering` é um tipo que determina a... a... 71 | ordem? Sim, a ordem relacionada às outras operações e às outras _threads_. 72 | Veja abaixo a definição de `Ordering`: 73 | 74 | ```rust 75 | pub enum Ordering { 76 | Relaxed, 77 | Release, 78 | Acquire, 79 | AcqRel, 80 | SeqCst, 81 | // some variants omitted 82 | } 83 | ``` 84 | 85 | Há, de modo ríspido, dois tipos de CPUs relacionados às ordens: os "fracos" 86 | e os "fortes". Os processadores "fracos" tem garantias naturalmente fracas a 87 | respeito das ordens, enquanto os processadores "fortes" tem garantias 88 | naturalmente fortes. Geralmente é de baixo custo para processadores "fortes" 89 | executarem `Acquire`, `Release` e `AcqRel`. Enquanto isso, é de alto custo para 90 | processadores "fracos" executarem estas ordens. Para todos eles, `Relaxed` é de 91 | baixo custo, e `SeqCst` é de alto custo. Exemplos de processadores "fracos" são 92 | os das arquiteturas ARM em geral e exemplos de "fortes" são os de arquiteturas 93 | x86/x86-64. 94 | 95 | As únicas variantes válidas para se passar a `load` são: `Relaxed`. `Acquire` e 96 | `SeqCst`. Não se preocupe, as outras variantes serão explicadas já já. `Relaxed` 97 | é algo como "a ordem não importa mesmo". Isso permite tanto o CPU quanto o 98 | compilador reordenarem a operação. `SeqCst` significa "sequencialmente 99 | consistente"; e não será reordenada de jeito nenhum: tudo antes da operação 100 | acontence antes, e tudo depois da operação acontece depois. 101 | 102 | `Acquire` é um pouco mais complexo. É o complementar de `Release`. Tudo 103 | (geralmente operações no estilo `store`) que acontecem depois de 104 | `Acquire` ficam depois de `Acquire`. Mas o compilador e o CPU são livres para 105 | reordenar tudo que ocorre antes de `Acquire`. Ele foi projetado para ser usado 106 | em operações do estilo `load` (carregar) ao adquir travas. 107 | 108 | Vejamos um exemplo com `AtomicBool::load`: 109 | 110 | ```rust 111 | use std::sync::atomic::{ 112 | AtomicBool, 113 | Ordering::*, 114 | }; 115 | 116 | fn print_if_it_is(atomic: &AtomicBool) { 117 | if atomic.load(Acquire) { 118 | println!("It is!"); 119 | } 120 | } 121 | ``` 122 | 123 | Agora vamos para a próxima operação: `store` (armazenar). `store` aceita uma 124 | referência para `self`, o novo valor (do tipo `bool`) e um `Ordering`. Os 125 | `Orderings`s válidos são `Relaxed`, `Release` e `SeqCst`. `Release`, como já 126 | mencionado, é usado junto a `Acquire` como um par. Tudo antes de um `Release` 127 | acontece antes dele, mas o CPU e o compilador são livres para reordenar tudo 128 | que há depois. A intenção é usá-lo ao soltar uma trava. 129 | 130 | Vejamos um exemplo: 131 | 132 | ```rust 133 | use std::sync::atomic::{ 134 | AtomicBool, 135 | Ordering::*, 136 | }; 137 | 138 | fn store_something(atomic: &AtomicBool) { 139 | atomic.store(false, Release); 140 | } 141 | ``` 142 | 143 | Você pode ter percebido duas coisas. Se não as percebeu, perceba agora. 144 | Primeiro: `store` precisa de uma referencia apenas imutável. Isso significa que 145 | ele não precisa de uma mutabilidade "externa", mas o atômico tem mutabilidade 146 | interna. Segundo: atômicos só são úteis em referências compartilhadas. Eles não 147 | tem nada como `clone`; para clonar você pode fazer algo como 148 | `let copied = AtomicBool::new(src.load(Acquire));`. Mas isso não compartilha o 149 | atômico. Desse modo, é comum encapsular o atômico (ou a estrutura que mantém 150 | um) em um `Arc`. 151 | 152 | Há, pelo menos, outras três operações importantes: `swap`, `compare_and_swap`, 153 | `compare_exchange_*`. `swap` (troca) é bastante simples: troca o argumento 154 | (do tipo `bool`) com o valor armazenado, e retorna o valor armazenado. `swap` 155 | aceita qualquer `Ordering`. `compare_and_swap` aceita um `bool`, dito "atual", 156 | outro `bool`, dito "novo", e o `Ordering` (qualquer um é válido). 157 | `compare_and_swap` é uma operação atômica bastante importante. Ela compara o 158 | argumento "atual" com o valor armazenado. Caso eles sejam iguais, a operação 159 | troca o valor armazenado com o argumento "novo". De qualquer forma, o valor 160 | armazenado é retornado. A operação obteve sucesso se o valor retornado é 161 | igual ao argumento "atual". 162 | 163 | Há ainda `compare_exchange_strong` (apenas `compare_exchange` em Rust) e 164 | `compare_exchange_weak` (que pode falhar espontaneamente). Estas são similares 165 | a `compare_and_swap`, exceto pelo fato de que aceitam duas ordens: uma para 166 | o caso de sucesso e uma para o caso de falha. Além disso, em Rust elas retornam 167 | um `Result`. O fato delas retornarem um `Result` possibilita 168 | `compare_exchange_weak` falhar mesmo que a comparação seja um sucesso. 169 | Importante: a ordem de sucesso aceita as mesmas variantes que `swap`, mas a de 170 | falha tem de ser igual ou mais fraca do que a de sucesso, além de ser válida 171 | para um `load`. 172 | 173 | Calma aí! Eu não expliquei ainda `Ordering::AcqRel`. Ele é o que parece: 174 | combina `Acquire` ao carregar e `Release` ao armazenar, para operações que 175 | carregam e armazenam atomicamente. Apesar de eu ter explicado tudo isso 176 | usando `AtomicBool`, essas operações são bastante comuns entre tipos de 177 | dados atômicos primitivos. Todos os tipos de dados atômicos do Rust têm 178 | pelo menos estas operações: `load`, `store`, `swap`, `compare_and_swap`, 179 | `compare_exchange` e `compare_exchange_weak`. Enfim, chega de conversa. 180 | Vamos agir. 181 | 182 | ## "E" lógico livre de travas (lock-free) 183 | 184 | A função abaixo recebe um booleano atômico, um booleano normal, armazena 185 | o resultado de um "E" lógico entre eles, e retorna o valor anterior. 186 | 187 | ```rust 188 | use std::sync::atomic::{AtomicBool, Ordering::{*, self}}; 189 | 190 | fn lockfree_and(x: &AtomicBool, y: bool, ord: Ordering) -> bool { 191 | let mut stored = x.load(match ord { 192 | AcqRel => Acquire, 193 | Release => Relaxed, 194 | o => o, 195 | }); 196 | loop { 197 | let inner = x.compare_and_swap(stored, stored && y, ord); 198 | if inner == stored { 199 | break inner; 200 | } 201 | stored = inner; 202 | } 203 | } 204 | ``` 205 | 206 | Note que os efeitos da operação só são visíveis após acabarmos. Ela é, de 207 | algum modo, "atômica". Geralmente, esse tipo de operação é chamada "lock-free" 208 | (livre de travas) porque ela não usa nenhuma forma de trava. Por mais que 209 | tenhamos um loop de tentativas, nós não dependemos de nenhuma _thread_ 210 | liberando o recurso. Não é uma trava! 211 | 212 | E, bem... é... Rust já fornece um método `AtomicBool::fetch_and` 213 | ("buscar 'e'"), que provavelmente é compilado para uma única instrução nativa. 214 | Eu quis apenas mostrar que você pode implementá-lo com os primitivos `load` e 215 | `compare_and_swap` via _software_. 216 | [Dê uma olhada aqui](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_and), 217 | temos outras operações em `AtomicBool`, tais como `nand` ("não 'e'"), `or` 218 | ("ou") e `xor` ("ou exclusivo"). 219 | 220 | Como você deve suspeitar, `AtomicUsize` e `AtomicIsize` tem seus próprios 221 | métodos com aritmética básica (adição e subtração) e bits. Todos eles são 222 | implementáveis via software, mas provavelmente são implementados para compilar 223 | para uma única instrução nativa. Apesar de a API não fornecer multiplicação e 224 | divisão, não é difícil de implementá-las. 225 | 226 | ## Nota sobre `AtomicPtr` 227 | 228 | `AtomicPtr` pode ser confuso. Os métodos `load` e `store` leem e escrevem 229 | o endereço ou o conteúdo do endereço? A resposta é: o endereço. Eles operam 230 | sobre um `*mut T`. Carregar o conteúdo é outra operação, que não é atômica e 231 | é bastante _unsafe_. 232 | 233 | ## `Send` e `Sync` 234 | 235 | Você talves tenha ouvido falar das _auto trait_s `Send` e `Sync`. Elas são 236 | bastante importantes em ambientes concorrentes. `T: Send` significa que `T` é 237 | seguro de ser mandado para outra _thread_. `T: Sync` significa que `&T` é 238 | seguro de ser compartilhado entre _threads_. Tipos de dados atômicos 239 | implementam tanto `Send` quanto `Sync`, então é seguro mandar e compartilhar 240 | esses tipos com _threads_. 241 | 242 | ## Bônus: implementação de spinlock 243 | 244 | ```rust 245 | pub mod spinlock { 246 | use std::{ 247 | cell::UnsafeCell, 248 | fmt, 249 | ops::{Deref, DerefMut}, 250 | sync::atomic::{ 251 | AtomicBool, 252 | Ordering::*, 253 | }, 254 | }; 255 | 256 | #[derive(Debug)] 257 | pub struct Mutex { 258 | locked: AtomicBool, 259 | inner: UnsafeCell, 260 | } 261 | 262 | #[derive(Debug, Clone, Copy)] 263 | pub struct MutexErr; 264 | 265 | pub struct MutexGuard<'a, T> 266 | where 267 | T: 'a 268 | { 269 | mutex: &'a Mutex, 270 | } 271 | 272 | impl Mutex { 273 | pub fn new(data: T) -> Self { 274 | Self { 275 | locked: AtomicBool::new(false), 276 | inner: UnsafeCell::new(data), 277 | } 278 | } 279 | 280 | pub fn try_lock<'a>(&'a self) -> Result, MutexErr> { 281 | if self.locked.swap(true, Acquire) { 282 | Err(MutexErr) 283 | } else { 284 | Ok(MutexGuard { 285 | mutex: self, 286 | }) 287 | } 288 | } 289 | 290 | pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> { 291 | loop { 292 | if let Ok(m) = self.try_lock() { 293 | break m; 294 | } 295 | } 296 | } 297 | } 298 | 299 | unsafe impl Send for Mutex 300 | where 301 | T: Send, 302 | { 303 | } 304 | 305 | unsafe impl Sync for Mutex 306 | where 307 | T: Send, 308 | { 309 | } 310 | 311 | impl Drop for Mutex { 312 | fn drop(&mut self) { 313 | unsafe { 314 | self.inner.get().drop_in_place() 315 | } 316 | } 317 | } 318 | 319 | impl<'a, T> Deref for MutexGuard<'a, T> { 320 | type Target = T; 321 | 322 | fn deref(&self) -> &T { 323 | unsafe { 324 | &*self.mutex.inner.get() 325 | } 326 | } 327 | } 328 | 329 | impl<'a, T> DerefMut for MutexGuard<'a, T> { 330 | fn deref_mut(&mut self) -> &mut T { 331 | unsafe { 332 | &mut *self.mutex.inner.get() 333 | } 334 | } 335 | } 336 | 337 | impl<'a, T> fmt::Debug for MutexGuard<'a, T> 338 | where 339 | T: fmt::Debug, 340 | { 341 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 342 | write!(fmtr, "{:?}", &**self) 343 | } 344 | } 345 | 346 | impl<'a, T> Drop for MutexGuard<'a, T> { 347 | fn drop(&mut self) { 348 | let _prev = self.mutex.locked.swap(false, Release); 349 | debug_assert!(_prev); 350 | } 351 | } 352 | 353 | } 354 | ``` 355 | --------------------------------------------------------------------------------