---
title: "Como Criar e Gerenciar Threads em Zig"
url: "https://ziglang.com.br/receitas/como-criar-e-gerenciar-threads-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/como-criar-e-gerenciar-threads-em-zig.MD"
description: "Aprenda a criar e gerenciar threads em Zig usando std.Thread para executar tarefas em paralelo, passar dados e sincronizar resultados de forma segura."
date: "2026-02-21"
author: "Zig Brasil"
---

# Como Criar e Gerenciar Threads em Zig

Aprenda a criar e gerenciar threads em Zig usando std.Thread para executar tarefas em paralelo, passar dados e sincronizar resultados de forma segura.


## Introdução

Threads permitem executar múltiplas tarefas simultaneamente, aproveitando os múltiplos núcleos do processador. Em Zig, a API `std.Thread` oferece uma interface direta para criar, gerenciar e sincronizar threads de forma segura.

Nesta receita, você aprenderá a criar threads, passar dados entre elas e sincronizar resultados.

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja o [guia de instalação](/tutoriais/como-instalar-zig/)
- Conhecimento básico de Zig. Consulte a [introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Criar uma Thread Simples

O exemplo mais básico: criar uma thread que executa uma função:

```zig
const std = @import("std");

fn tarefa() void {
    std.debug.print("Olá da thread!\n", .{});
}

pub fn main() !void {
    // Criar e iniciar a thread
    const thread = try std.Thread.spawn(.{}, tarefa, .{});

    // Esperar a thread terminar
    thread.join();

    std.debug.print("Thread concluída. Main continua.\n", .{});
}
```

### Saída esperada

```
Olá da thread!
Thread concluída. Main continua.
```

## Passar Argumentos para Threads

Passe dados para a função da thread:

```zig
const std = @import("std");

fn calcularSoma(inicio: u64, fim: u64) u64 {
    var soma: u64 = 0;
    var i = inicio;
    while (i <= fim) : (i += 1) {
        soma += i;
    }
    std.debug.print("Soma de {d} a {d} = {d}\n", .{ inicio, fim, soma });
    return soma;
}

fn threadCalculo(inicio: u64, fim: u64) void {
    _ = calcularSoma(inicio, fim);
}

pub fn main() !void {
    // Criar múltiplas threads com argumentos diferentes
    const t1 = try std.Thread.spawn(.{}, threadCalculo, .{ 1, 1000 });
    const t2 = try std.Thread.spawn(.{}, threadCalculo, .{ 1001, 2000 });
    const t3 = try std.Thread.spawn(.{}, threadCalculo, .{ 2001, 3000 });

    // Esperar todas terminarem
    t1.join();
    t2.join();
    t3.join();

    std.debug.print("Todos os cálculos concluídos.\n", .{});
}
```

## Threads com Dados Compartilhados

Use ponteiros para compartilhar dados entre threads (com cuidado):

```zig
const std = @import("std");

const Contador = struct {
    valor: std.atomic.Value(u64),

    pub fn init() Contador {
        return .{
            .valor = std.atomic.Value(u64).init(0),
        };
    }

    pub fn incrementar(self: *Contador) void {
        _ = self.valor.fetchAdd(1, .seq_cst);
    }

    pub fn get(self: *Contador) u64 {
        return self.valor.load(.seq_cst);
    }
};

fn workerThread(contador: *Contador, n: u32) void {
    for (0..n) |_| {
        contador.incrementar();
    }
}

pub fn main() !void {
    var contador = Contador.init();

    const num_threads = 4;
    const incrementos_por_thread = 10000;

    var threads: [num_threads]std.Thread = undefined;

    // Iniciar threads
    for (&threads) |*t| {
        t.* = try std.Thread.spawn(.{}, workerThread, .{
            &contador,
            incrementos_por_thread,
        });
    }

    // Esperar todas terminarem
    for (&threads) |t| {
        t.join();
    }

    const total = contador.get();
    const esperado = num_threads * incrementos_por_thread;
    std.debug.print("Total: {d} (esperado: {d})\n", .{ total, esperado });
    std.debug.print("Correto: {}\n", .{total == esperado});
}
```

### Saída esperada

```
Total: 40000 (esperado: 40000)
Correto: true
```

## Criar Múltiplas Threads Dinamicamente

Use um allocator para criar um número variável de threads:

```zig
const std = @import("std");

fn processarItem(id: usize) void {
    // Simular trabalho
    std.time.sleep(std.time.ns_per_ms * 100);
    std.debug.print("Item {d} processado pela thread\n", .{id});
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const num_itens: usize = 8;

    // Alocar array de threads
    const threads = try allocator.alloc(std.Thread, num_itens);
    defer allocator.free(threads);

    // Iniciar todas as threads
    for (0..num_itens) |i| {
        threads[i] = try std.Thread.spawn(.{}, processarItem, .{i});
    }

    std.debug.print("Todas as {d} threads iniciadas. Aguardando...\n", .{num_itens});

    // Esperar todas
    for (threads) |thread| {
        thread.join();
    }

    std.debug.print("Todos os itens processados!\n", .{});
}
```

## Thread com Detach

Para threads que não precisam ser aguardadas:

```zig
const std = @import("std");

fn backgroundTask() void {
    std.debug.print("Tarefa em background iniciada.\n", .{});
    std.time.sleep(std.time.ns_per_s * 1);
    std.debug.print("Tarefa em background concluída.\n", .{});
}

pub fn main() !void {
    const thread = try std.Thread.spawn(.{}, backgroundTask, .{});

    // Detach: thread continua independente
    thread.detach();

    std.debug.print("Main continua sem esperar a thread.\n", .{});

    // Precisamos esperar um pouco para a thread terminar antes do processo sair
    std.time.sleep(std.time.ns_per_s * 2);
}
```

## Padrão Produtor-Consumidor Simples

Threads coordenadas com dados atômicos:

```zig
const std = @import("std");

const FilaSimples = struct {
    itens: [256]u32 = undefined,
    head: std.atomic.Value(usize),
    tail: std.atomic.Value(usize),

    pub fn init() FilaSimples {
        return .{
            .head = std.atomic.Value(usize).init(0),
            .tail = std.atomic.Value(usize).init(0),
        };
    }

    pub fn push(self: *FilaSimples, valor: u32) bool {
        const tail = self.tail.load(.seq_cst);
        const next_tail = (tail + 1) % 256;
        if (next_tail == self.head.load(.seq_cst)) return false; // cheio
        self.itens[tail] = valor;
        self.tail.store(next_tail, .seq_cst);
        return true;
    }

    pub fn pop(self: *FilaSimples) ?u32 {
        const head = self.head.load(.seq_cst);
        if (head == self.tail.load(.seq_cst)) return null; // vazio
        const valor = self.itens[head];
        self.head.store((head + 1) % 256, .seq_cst);
        return valor;
    }
};

fn produtor(fila: *FilaSimples) void {
    for (0..20) |i| {
        while (!fila.push(@intCast(i))) {
            std.time.sleep(std.time.ns_per_ms);
        }
        std.debug.print("Produzido: {d}\n", .{i});
    }
}

fn consumidor(fila: *FilaSimples) void {
    var consumidos: u32 = 0;
    while (consumidos < 20) {
        if (fila.pop()) |valor| {
            std.debug.print("  Consumido: {d}\n", .{valor});
            consumidos += 1;
        } else {
            std.time.sleep(std.time.ns_per_ms);
        }
    }
}

pub fn main() !void {
    var fila = FilaSimples.init();

    const t_prod = try std.Thread.spawn(.{}, produtor, .{&fila});
    const t_cons = try std.Thread.spawn(.{}, consumidor, .{&fila});

    t_prod.join();
    t_cons.join();

    std.debug.print("Produtor-consumidor concluído!\n", .{});
}
```

## Dicas e Boas Práticas

1. **Sempre join ou detach**: Toda thread criada deve ser finalizada com `join()` (espera) ou `detach()` (independente).

2. **Cuidado com dados compartilhados**: Use [operações atômicas](/receitas/zig-atomic-operacoes/) ou [mutex](/receitas/zig-mutex-exemplo/) para proteger dados compartilhados.

3. **Não crie threads demais**: O número ideal geralmente é próximo ao número de cores da CPU. Use [thread pools](/receitas/zig-thread-pool/).

4. **Stack size**: Configure `.stack_size` em `std.Thread.SpawnConfig` se a thread precisar de mais stack.

5. **Evite data races**: O Zig não previne data races automaticamente. Use sincronização adequada.

## Receitas Relacionadas

- [Como usar Mutex em Zig](/receitas/zig-mutex-exemplo/) - Sincronização entre threads
- [Como usar Thread Pool em Zig](/receitas/zig-thread-pool/) - Pool de threads reutilizáveis
- [Como usar operações atômicas em Zig](/receitas/zig-atomic-operacoes/) - Operações sem lock
- [Como usar canais de comunicação em Zig](/receitas/zig-canal-comunicacao/) - Comunicação entre threads

## Tutoriais Relacionados

- [Concorrência em Zig](/tutoriais/concorrencia-em-zig/)
- [Gerenciamento de Memória em Zig](/tutoriais/gerenciamento-de-memoria-zig/)
