Introducció
La multifil i la programació paral·lela són conceptes avançats que permeten als programes executar múltiples tasques simultàniament, millorant així el rendiment i l'eficiència. En aquest tema, explorarem com utilitzar fils (threads) i tasques (tasks) en C# per aconseguir una execució concurrent i paral·lela.
Objectius
- Comprendre els conceptes bàsics de la multifil i la programació paral·lela.
- Aprendre a crear i gestionar fils en C#.
- Utilitzar la biblioteca de tasques paral·leles (TPL) per a la programació paral·lela.
- Implementar patrons comuns de programació concurrent.
Conceptes Clau
- Fils (Threads)
Un fil és la unitat bàsica d'execució en un programa. Cada fil pot executar una tasca independentment dels altres fils.
- Programació Paral·lela
La programació paral·lela implica dividir una tasca en sub-tasques que es poden executar simultàniament en múltiples fils o processadors.
- Biblioteca de Tasques Paral·leles (TPL)
La TPL és una biblioteca de .NET que facilita la creació i gestió de tasques paral·leles.
Creació i Gestió de Fils
Exemple Bàsic de Fils
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
thread.Join(); // Espera que el fil acabi
Console.WriteLine("Fil principal acabat.");
}
static void DoWork()
{
Console.WriteLine("Treballant en un fil separat.");
}
}Explicació:
Thread thread = new Thread(new ThreadStart(DoWork));: Crea un nou fil que executarà el mètodeDoWork.thread.Start();: Inicia l'execució del fil.thread.Join();: Espera que el fil acabi abans de continuar amb el fil principal.
Sincronització de Fils
Quan múltiples fils accedeixen a recursos compartits, és important sincronitzar-los per evitar condicions de carrera.
Exemple amb lock
using System;
using System.Threading;
class Program
{
private static readonly object _lock = new object();
private static int _counter = 0;
static void Main()
{
Thread thread1 = new Thread(IncrementCounter);
Thread thread2 = new Thread(IncrementCounter);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Counter: {_counter}");
}
static void IncrementCounter()
{
for (int i = 0; i < 1000; i++)
{
lock (_lock)
{
_counter++;
}
}
}
}Explicació:
lock (_lock): Assegura que només un fil pugui accedir al bloc de codi protegit al mateix temps.
Biblioteca de Tasques Paral·leles (TPL)
Exemple Bàsic amb Task
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Task task = Task.Run(() => DoWork());
task.Wait(); // Espera que la tasca acabi
Console.WriteLine("Fil principal acabat.");
}
static void DoWork()
{
Console.WriteLine("Treballant en una tasca separada.");
}
}Explicació:
Task task = Task.Run(() => DoWork());: Crea i inicia una nova tasca que executarà el mètodeDoWork.task.Wait();: Espera que la tasca acabi abans de continuar amb el fil principal.
Paral·lelisme amb Parallel.For
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Parallel.For(0, 10, i =>
{
Console.WriteLine($"Treballant en l'índex {i}");
});
}
}Explicació:
Parallel.For(0, 10, i => { ... });: Executa el bloc de codi per a cada valor deien paral·lel.
Exercicis Pràctics
Exercici 1: Crear i Gestionar Fils
Descripció:
Crea un programa que iniciï dos fils separats. Cada fil ha d'incrementar un comptador compartit 1000 vegades. Utilitza lock per sincronitzar l'accés al comptador.
Solució:
using System;
using System.Threading;
class Program
{
private static readonly object _lock = new object();
private static int _counter = 0;
static void Main()
{
Thread thread1 = new Thread(IncrementCounter);
Thread thread2 = new Thread(IncrementCounter);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Counter: {_counter}");
}
static void IncrementCounter()
{
for (int i = 0; i < 1000; i++)
{
lock (_lock)
{
_counter++;
}
}
}
}Exercici 2: Utilitzar Task per a la Programació Paral·lela
Descripció:
Crea un programa que utilitzi Task per executar tres tasques paral·leles. Cada tasca ha de mostrar un missatge diferent.
Solució:
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Task task1 = Task.Run(() => Console.WriteLine("Tasca 1"));
Task task2 = Task.Run(() => Console.WriteLine("Tasca 2"));
Task task3 = Task.Run(() => Console.WriteLine("Tasca 3"));
Task.WaitAll(task1, task2, task3);
Console.WriteLine("Totes les tasques han acabat.");
}
}Resum
En aquesta secció, hem après els conceptes bàsics de la multifil i la programació paral·lela en C#. Hem vist com crear i gestionar fils, com sincronitzar-los per evitar condicions de carrera, i com utilitzar la biblioteca de tasques paral·leles (TPL) per a la programació paral·lela. A més, hem practicat aquests conceptes amb exercicis pràctics.
En el següent mòdul, explorarem altres conceptes avançats de C#, com la reflexió i els atributs.
Curs de Programació en C#
Mòdul 1: Introducció al C#
- Introducció al C#
- Configuració de l'Entorn de Desenvolupament
- Programa Hello World
- Sintaxi i Estructura Bàsica
- Variables i Tipus de Dades
Mòdul 2: Estructures de Control
Mòdul 3: Programació Orientada a Objectes
Mòdul 4: Conceptes Avançats de C#
- Interfícies
- Delegats i Esdeveniments
- Genèrics
- Col·leccions
- LINQ (Consulta Integrada al Llenguatge)
- Programació Asíncrona
Mòdul 5: Treballant amb Dades
Mòdul 6: Temes Avançats
- Reflexió
- Atributs
- Programació Dinàmica
- Gestió de Memòria i Recollida d'Escombraries
- Multifil i Programació Paral·lela
Mòdul 7: Construcció d'Aplicacions
Mòdul 8: Millors Pràctiques i Patrons de Disseny
- Estàndards de Codificació i Millors Pràctiques
- Patrons de Disseny
- Proves Unitàries
- Revisió de Codi i Refactorització
