<h2>Send: Transferência Segura Entre Threads</h2>
<p><code>Send</code> é um trait que garante que um valor pode ser movido com segurança entre threads. Quando você implementa <code>Send</code>, você afirma: "este tipo é seguro para ser transferido para outra thread de execução". A maioria dos tipos em Rust implementa <code>Send</code> automaticamente, exceto aqueles que contêm referências não-seguras ou ponteiros brutos.</p>
<pre><code class="language-rust">use std::thread;
#[derive(Clone)]
struct Mensagem {
conteudo: String,
}
impl Send for Mensagem {} // Implementação explícita (redundante aqui, só para demonstrar)
fn main() {
let msg = Mensagem {
conteudo: "Olá de outra thread".to_string(),
};
let handle = thread::spawn(move || {
println!("Recebido: {}", msg.conteudo);
});
handle.join().unwrap();
}</code></pre>
<p>Tipos que <strong>não</strong> implementam <code>Send</code> incluem <code>Rc<T></code> (referência compartilhada não-thread-safe) e <code>Cell<T></code>. Tentar enviar esses para outra thread resultará em erro de compilação, protegendo você de data races em tempo de compilação, não em tempo de execução.</p>
<h2>Sync: Compartilhamento Seguro Entre Threads</h2>
<p><code>Sync</code> garante que referências a um valor podem ser compartilhadas com segurança entre threads. Um tipo <code>T</code> é <code>Sync</code> se <code>&T</code> é <code>Send</code>. Isso significa que múltiplas threads podem acessar o mesmo valor simultaneamente sem corrupção de dados.</p>
<pre><code class="language-rust">use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let contador = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..5 {
let contador_clone = Arc::clone(&contador);
let handle = thread::spawn(move || {
let mut num = contador_clone.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Contador final: {}", *contador.lock().unwrap());
}</code></pre>
<p><code>Arc<T></code> (Atomic Reference Counting) permite compartilhamento de propriedade entre threads, e <code>Mutex<T></code> fornece exclusão mútua. Juntos, <code>Arc<Mutex<T>></code> é simultaneamente <code>Send</code> e <code>Sync</code>, tornando-o ideal para estado compartilhado thread-safe.</p>
<h2>O Impacto da Segurança em Tempo de Compilação</h2>
<p>A verdadeira revolução de Rust é que estas garantias são verificadas <strong>antes</strong> de você executar uma única linha de código. Linguagens como Java e Python dependem de locks em tempo de execução e testes extensivos. Rust elimina classes inteiras de bugs antes da compilação.</p>
<pre><code class="language-rust">// Este código NÃO compila:
use std::rc::Rc;
use std::thread;
fn main() {
let rc = Rc::new(5);
thread::spawn(move || {
println!("{}", rc);
});
// erro: Rc<i32> cannot be sent between threads safely
}
// Solução: usar Arc em vez de Rc
use std::sync::Arc;
fn main() {
let arc = Arc::new(5);
thread::spawn(move || {
println!("{}", arc);
}).join().unwrap();
}</code></pre>
<p>O compilador força você a escolher as primitivas corretas desde o início. Não há surpresas em produção: se compila, é seguro. Essa abordagem previne deadlocks sutis, race conditions e memory safety issues que afetam sistemas concorrentes em outras linguagens.</p>
<h2>Traits Automáticos e Casos Avançados</h2>
<h3>Implementação Automática</h3>
<p>Rust implementa <code>Send</code> e <code>Sync</code> <strong>automaticamente</strong> para tipos que atendem aos critérios:</p>
<ul>
<li>Um struct é <code>Send</code> se todos seus campos são <code>Send</code></li>
<li>Um struct é <code>Sync</code> se todos seus campos são <code>Sync</code></li>
</ul>
<pre><code class="language-rust">struct Seguro {
valor: i32, // i32 é Send + Sync
texto: String, // String é Send + Sync
}
// Seguro é automaticamente Send + Sync
struct Inseguro {
ponteiro: const u8, // const não implementa Send
}
// Inseguro NÃO é Send/Sync (risco: dados não-sincronizados)</code></pre>
<h3>Casos Avançados: Negação Explícita</h3>
<p>Ocasionalmente, você quer <strong>impedir</strong> que um tipo seja <code>Send</code> ou <code>Sync</code>, mesmo que todos os campos permitam:</p>
<pre><code class="language-rust">use std::marker::PhantomData;
struct NaoEnviavel {
dados: String,
_phantom: PhantomData<const ()>, // const não é Send
}
// NaoEnviavel agora é !Send mesmo que String seja Send</code></pre>
<p>Isso é útil quando seu tipo encapsula invariantes específicas de thread que não devem ser violadas.</p>
<h2>Conclusão</h2>
<p>Aprendemos que <strong>Send e Sync são os pilares da segurança de concorrência em Rust</strong>. Send garante movimentação segura entre threads, enquanto Sync permite compartilhamento seguro de referências. O brilho dessa abordagem é que essas garantias são <strong>verificadas em tempo de compilação</strong>, eliminando race conditions e deadlocks antes da execução. Use <code>Arc<Mutex<T>></code> para estado compartilhado, respeite as restrições do compilador, e você construirá sistemas concorrentes robustos e eficientes.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch16-00-concurrency.html" target="_blank" rel="noopener noreferrer">The Rust Programming Language - Fearless Concurrency (Capítulo 16)</a></li>
<li><a href="https://doc.rust-lang.org/std/marker/trait.Send.html" target="_blank" rel="noopener noreferrer">Rust std::marker::Send Documentation</a></li>
<li><a href="https://doc.rust-lang.org/std/marker/trait.Sync.html" target="_blank" rel="noopener noreferrer">Rust std::marker::Sync Documentation</a></li>
<li><a href="https://tokio.rs/" target="_blank" rel="noopener noreferrer">Tokio Runtime - Advanced Concurrency Patterns</a></li>
<li><a href="https://www.youtube.com/watch?v=3AwQoWf6lb8" target="_blank" rel="noopener noreferrer">Jon Gjengset - Crust of Rust: Concurrency (YouTube)</a></li>
</ul>