Multiple Instruction Multiple Data - MIMD


Na taxonomia de Flynn, MIMD significa “Multiple Instruction, Multiple Data” (Múltiplas Instruções, Múltiplos Dados).

Nesse modelo, várias unidades de processamento operam de forma independente, executando diferentes instruções sobre diferentes conjuntos de dados simultaneamente.

Note

É o modelo mais flexível e poderoso da taxonomia, pois permite tanto o paralelismo de instruções quanto o paralelismo de dados.

Principais características:

  • Cada processador ou thread pode executar sua própria sequência de instruções.
  • Cada unidade trabalha com seu próprio conjunto de dados.
  • Amplamente utilizado em sistemas multicore, clusters de computadores e supercomputadores.

Note

O MIMD é comum em arquiteturas modernas, como CPUs multicore (onde cada núcleo executa um programa diferente) e sistemas distribuídos (como servidores em uma rede).

Exemplo

Imagine um sistema de processamento de pedidos em um restaurante. Há várias tarefas acontecendo ao mesmo tempo:

  1. Um cozinheiro prepara um prato principal (dado: receita do prato).
  2. Outro cozinheiro faz uma sobremesa (dado: receita da sobremesa).
  3. Um garçom anota pedidos dos clientes (dado: lista de pedidos).

Aqui, cada “processador” (cozinheiro ou garçom) executa uma instrução diferente (preparar prato, fazer sobremesa, anotar pedidos) sobre um conjunto de dados distinto (receita do prato, receita da sobremesa, lista de pedidos). As tarefas são independentes e ocorrem em paralelo, refletindo o modelo MIMD.

Aplicação em Código (C++)

Cada thread executará uma tarefa diferente sobre um conjunto de dados distinto.

#include <iostream>
#include <thread>
#include <vector>
#include <string>
using namespace std;
 
// Função para simular o preparo do prato principal
void prepararPrato(string receita) {
    cout << "Cozinheiro 1: Preparando prato principal com " << receita << endl;
    // Simula trabalho (ex.: cozinhar por 2 segundos)
    this_thread::sleep_for(chrono::seconds(2));
    cout << "Cozinheiro 1: Prato principal pronto!" << endl;
}
 
// Função para simular o preparo da sobremesa
void prepararSobremesa(string receita) {
    cout << "Cozinheiro 2: Preparando sobremesa com " << receita << endl;
    // Simula trabalho (ex.: cozinhar por 1 segundo)
    this_thread::sleep_for(chrono::seconds(1));
    cout << "Cozinheiro 2: Sobremesa pronta!" << endl;
}
 
// Função para simular a anotação de pedidos
void anotarPedidos(vector<string>& pedidos) {
    cout << "Garçom: Anotando pedidos..." << endl;
    pedidos.push_back("Prato principal");
    pedidos.push_back("Sobremesa");
    // Simula trabalho (ex.: 1.5 segundos)
    this_thread::sleep_for(chrono::milliseconds(1500));
    cout << "Garçom: Pedidos anotados: ";
    for (const auto& pedido : pedidos) {
        cout << pedido << " ";
    }
    cout << endl;
}
 
int main() {
    // Dados distintos para cada tarefa
    string receitaPrato = "macarrão com molho";
    string receitaSobremesa = "bolo de chocolate";
    vector<string> listaPedidos;
 
    // Criação das threads (unidades de processamento independentes)
    thread t1(prepararPrato, receitaPrato);         // Thread 1: Cozinheiro 1
    thread t2(prepararSobremesa, receitaSobremesa); // Thread 2: Cozinheiro 2
    thread t3(anotarPedidos, ref(listaPedidos));    // Thread 3: Garçom
 
    // Aguarda as threads terminarem
    t1.join();
    t2.join();
    t3.join();
 
    cout << "Todas as tarefas foram concluídas!" << endl;
 
    return 0;
}
  1. Dados distintos:

    • receitaPrato (“macarrão com molho”) é o dado para a tarefa do prato principal.
    • receitaSobremesa (“bolo de chocolate”) é o dado para a tarefa da sobremesa.
    • listaPedidos (um vetor) é o dado para a tarefa de anotação de pedidos.
  2. Múltiplas instruções:

    • prepararPrato: Simula o preparo do prato principal.
    • prepararSobremesa: Simula o preparo da sobremesa.
    • anotarPedidos: Simula a anotação de pedidos.
    • Cada função representa uma sequência de instruções diferente.
  3. Paralelismo com threads:

    • Três threads (t1, t2, t3) são criadas, cada uma executando uma função diferente sobre seu próprio dado.
    • As threads rodam em paralelo (em um sistema multicore, elas podem ser executadas em núcleos diferentes), refletindo o MIMD.
  4. Saída:

    • A execução das tarefas ocorre simultaneamente, e a ordem das mensagens no console pode variar dependendo do escalonamento das threads. Exemplo de saída possível:
    Cozinheiro 1: Preparando prato principal com macarrão com molho
    Cozinheiro 2: Preparando sobremesa com bolo de chocolate
    Garçom: Anotando pedidos...
    Cozinheiro 2: Sobremesa pronta!
    Garçom: Pedidos anotados: Prato principal Sobremesa
    Cozinheiro 1: Prato principal pronto!
    Todas as tarefas foram concluídas!
    

O MIMD é o modelo mais versátil da taxonomia de Flynn, amplamente implementado em sistemas multicore e distribuídos. No exemplo do restaurante, diferentes tarefas (instruções) foram executadas em paralelo sobre diferentes dados, ilustrando como o MIMD é adequado para problemas complexos e independentes. Em arquiteturas modernas, o MIMD é a base para computação de alto desempenho, como em servidores, jogos e simulações científicas.

Referências


Aula 06-03-2025