Introducció al Multifil

El multifil (multithreading) és una tècnica de programació que permet executar múltiples fils (threads) de manera concurrent dins d'un mateix procés. Això pot millorar significativament el rendiment d'una aplicació, especialment en sistemes amb múltiples nuclis de CPU.

Conceptes Clau

  • Fil (Thread): Un fil és la unitat més petita d'execució que pot ser gestionada pel sistema operatiu.
  • Procés: Un procés és un programa en execució que pot contenir múltiples fils.
  • Concurrència: La capacitat d'executar múltiples tasques al mateix temps.
  • Paral·lelisme: L'execució simultània de múltiples tasques en diferents nuclis de CPU.

Creació de Fils en C++

En C++, la biblioteca <thread> proporciona les eines necessàries per treballar amb fils. A continuació es mostra un exemple bàsic de com crear i gestionar fils.

Exemple Bàsic

#include <iostream>
#include <thread>

// Funció que serà executada en un fil separat
void funcioFil() {
    std::cout << "Hola des del fil!" << std::endl;
}

int main() {
    // Crear un fil que executa la funció 'funcioFil'
    std::thread fil(funcioFil);

    // Esperar que el fil acabi
    fil.join();

    std::cout << "Hola des del fil principal!" << std::endl;

    return 0;
}

Explicació del Codi

  1. Incloure la Biblioteca <thread>: Necessària per treballar amb fils.
  2. Funció funcioFil: Aquesta funció serà executada en un fil separat.
  3. Crear un Fil: Utilitzem el constructor de std::thread per crear un nou fil que executa funcioFil.
  4. Esperar que el Fil Acabi: Utilitzem join() per esperar que el fil acabi abans de continuar amb el fil principal.

Sincronització de Fils

Quan múltiples fils accedeixen a recursos compartits, és crucial sincronitzar-los per evitar condicions de carrera (race conditions). La biblioteca <mutex> proporciona mecanismes per a la sincronització.

Exemple amb std::mutex

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void funcioFil(int id) {
    // Bloquejar el mutex
    mtx.lock();
    std::cout << "Fil " << id << " està executant" << std::endl;
    // Desbloquejar el mutex
    mtx.unlock();
}

int main() {
    std::thread fils[5];

    // Crear 5 fils
    for (int i = 0; i < 5; ++i) {
        fils[i] = std::thread(funcioFil, i);
    }

    // Esperar que tots els fils acabin
    for (int i = 0; i < 5; ++i) {
        fils[i].join();
    }

    return 0;
}

Explicació del Codi

  1. Incloure la Biblioteca <mutex>: Necessària per treballar amb mutex.
  2. Crear un std::mutex: Un objecte mutex per a la sincronització.
  3. Bloquejar i Desbloquejar el Mutex: Utilitzem mtx.lock() i mtx.unlock() per assegurar que només un fil accedeixi a la secció crítica al mateix temps.

Exercicis Pràctics

Exercici 1: Crear i Gestionar Fils

Descripció: Escriu un programa que creï tres fils, cadascun dels quals imprimeixi un missatge diferent.

Solució:

#include <iostream>
#include <thread>

void funcioFil1() {
    std::cout << "Fil 1 està executant" << std::endl;
}

void funcioFil2() {
    std::cout << "Fil 2 està executant" << std::endl;
}

void funcioFil3() {
    std::cout << "Fil 3 està executant" << std::endl;
}

int main() {
    std::thread fil1(funcioFil1);
    std::thread fil2(funcioFil2);
    std::thread fil3(funcioFil3);

    fil1.join();
    fil2.join();
    fil3.join();

    return 0;
}

Exercici 2: Sincronització amb std::mutex

Descripció: Modifica l'exemple anterior per utilitzar un std::mutex per sincronitzar l'accés a la consola.

Solució:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void funcioFil(int id) {
    mtx.lock();
    std::cout << "Fil " << id << " està executant" << std::endl;
    mtx.unlock();
}

int main() {
    std::thread fils[3];

    for (int i = 0; i < 3; ++i) {
        fils[i] = std::thread(funcioFil, i + 1);
    }

    for (int i = 0; i < 3; ++i) {
        fils[i].join();
    }

    return 0;
}

Errors Comuns i Consells

  • Oblidar join(): Si no esperes que els fils acabin amb join(), el programa pot acabar abans que els fils hagin completat la seva execució.
  • Condicions de Carrera: Sempre utilitza mecanismes de sincronització com std::mutex quan múltiples fils accedeixen a recursos compartits.
  • Bloqueig de Mutex: Assegura't de desbloquejar el mutex després d'usar-lo per evitar bloquejos (deadlocks).

Conclusió

El multifil és una tècnica poderosa per millorar el rendiment de les aplicacions, però requereix una gestió acurada per evitar problemes de concurrència. Amb els conceptes i exemples proporcionats, hauríeu de tenir una bona base per començar a treballar amb fils en C++.

© Copyright 2024. Tots els drets reservats