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 dei
en 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ó