Shembuj per sinkronizimin e threadeve
Shembull 1 - Shuma e 10 numrave pa lock
Skedari Program.cs
using Processes;
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static void Main()
{
MultiThreads multiThreads = new MultiThreads();
}
}
Skedari MultiThreads.cs
using System.Diagnostics;
using System;
using System.Diagnostics;
using System.Threading;
class MultiThreads
{
public MultiThreads()
{
string s;
Console.WriteLine("MultiThreads");
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
Console.WriteLine("summing numbers sequentialy");
Stopwatch stopwatch = Stopwatch.StartNew();
foreach (var number in numbers)
{
sum += ProcessNumber(number);
}
stopwatch.Stop();
Console.WriteLine($"Sequential Sum: {sum}, Time taken: {stopwatch.ElapsedMilliseconds} ms");
s=Console.ReadLine();
sum = 0;
stopwatch.Reset();
stopwatch.Start();
Console.WriteLine("summing numbers in parallel");
// Parallel Calculation
Parallel.ForEach(numbers, number =>
{
sum += ProcessNumber(number);
});
stopwatch.Stop();
Console.WriteLine($"Parallel Sum: {sum}, Time taken: {stopwatch.ElapsedMilliseconds} ms");
s = Console.ReadLine();
}
static int ProcessNumber(int number)
{
Thread.Sleep(TimeSpan.FromMilliseconds(100));
Console.WriteLine(number.ToString());
return number;
}
}
Shenime
Sic e shpjeguam vini re ekzekutimin. Shuma e llogaritur me ParallelForEach nuk eshte e sakte.
Arsyetoni pse?
Shuma e numrave e korrigjuar me lock.
Tani rezultati i shumes eshte korrekt. A perfitoni ne kohe?
Skedari Main.cs eshte i njejte.
Skedari MultiThreads.cs
using System.Diagnostics;
using System;
using System.Diagnostics;
using System.Threading;
class MultiThreads
{
public MultiThreads()
{
object _lockObj = new object();
string s;
Console.WriteLine("MultiThreads");
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
Console.WriteLine("summing numbers sequentialy");
Stopwatch stopwatch = Stopwatch.StartNew();
foreach (var number in numbers)
{
sum += ProcessNumber(number);
}
stopwatch.Stop();
Console.WriteLine($"Sequential Sum: {sum}, Time taken: {stopwatch.ElapsedMilliseconds} ms");
s=Console.ReadLine();
sum = 0;
stopwatch.Reset();
stopwatch.Start();
Console.WriteLine("summing numbers in parallel");
// Parallel Calculation
Parallel.ForEach(numbers, number =>
{
lock (_lockObj)
{
sum += ProcessNumber(number);
}
});
stopwatch.Stop();
Console.WriteLine($"Parallel Sum: {sum}, Time taken: {stopwatch.ElapsedMilliseconds} ms");
s = Console.ReadLine();
}
static int ProcessNumber(int number)
{
Thread.Sleep(TimeSpan.FromMilliseconds(100));
Console.WriteLine(number.ToString());
return number;
}
}
Ndryshimet jane shenuar me ngjyre te kuqe.
Eshte deklaruar object _lockObj = new object();
i cili perdoret me pas per te kycur nje pjese te kodit te metodes:
lock (_lockObj)
{
sum += ProcessNumber(number);
}
Kjo ben qe kjo pjese e kodit te thread te ekzekutohet ne menyre konkurente, pra qe nese njeri thread hyn ne kete pjese te kodit te tjeret duhet te presin qe ai thread te perfundoje kete pjese te kodit perpara se ssa thread e tjera te hyjne ne kete pjese te kodit. Pra derisa thread qe e mori lock i pari ta liroje ate.
Kjo garanton nje rezultat te sakte edhe te llogaritjes ne paralel te shumes.
Skedari main.cs
using System;
using System.Threading;
namespace Threads
{
class Program
{
static void Main()
{
BankAccount account = new BankAccount(1000); // Initial balance
Console.WriteLine();
Console.WriteLine("-------------------------------------------------------------------------");
Console.WriteLine("A realistic Program planning:");
Console.WriteLine("My parents deposited in my bank account :" + account.balance.ToString()+" euro.");
Thread t1 = new Thread(() => account.Deposit(500)) { Name = "Salary Payment" };
Thread t2 = new Thread(() => account.Withdraw(700)) { Name = "Birthday Party Invoice Payment" };
Thread t3 = new Thread(() => account.Withdraw(1000)) { Name = "Get Money for Rent" };
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
Console.WriteLine("Final balance: " + account.balance);
// this is magic code
MagicBankAccount MagicAccount = new MagicBankAccount(1000); // Initial balance
Console.WriteLine();
Console.WriteLine("-------------------------------------------------------------------------");
Console.WriteLine("A Magic Program planning. I hope developers didnt learn thread synchronization");
Console.WriteLine("My parents deposited in my bank account :" + MagicAccount.balance.ToString() + " euro.");
Thread t4 = new Thread(() => MagicAccount.Deposit(500)) { Name = "Salary Payment" };
Thread t5 = new Thread(() => MagicAccount.Withdraw(700)) { Name = "Birthday Party Invoice Payment" };
Thread t6 = new Thread(() => MagicAccount.Withdraw(1000)) { Name = "Get Money for Rent" };
t4.Start();
t5.Start();
t6.Start();
t4.Join();
t5.Join();
t6.Join();
Console.WriteLine("Final balance: " + account.balance);
Console.WriteLine("-------------------------------------------------------------------------");
Console.WriteLine("Thank you guys programming the bank software!!!!");
Console.WriteLine("I paid all my expenses and I still have money on my bank account");
Console.WriteLine("Pleased do not learn thread synchronization!!!");
}
}
}
Skedari BankAccount.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Threads
{
class BankAccount
{
public decimal balance;
private readonly object _lockObj = new object(); // Lock object
public BankAccount(decimal initialBalance)
{
balance = initialBalance;
}
public void Deposit(decimal amount)
{
lock (_lockObj) // Ensures thread safety
{
balance += amount;
Console.WriteLine($"{Thread.CurrentThread.Name} deposited {amount} euro, New Balance: {balance} euro");
}
}
public void Withdraw(decimal amount)
{
lock (_lockObj) // Ensures thread safety
{
if (balance >= amount)
{
balance -= amount;
Console.WriteLine($"{Thread.CurrentThread.Name} withdrew {amount} euro, New Balance: {balance} euro");
}
else
{
Console.WriteLine($"{Thread.CurrentThread.Name} attempted to withdraw {amount} euro, but insufficient funds!");
}
}
}
}
}
Skedari MagicBankAccount
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Threads
{
class MagicBankAccount
{
public decimal balance;
public MagicBankAccount(decimal initialBalance)
{
balance = initialBalance;
}
public void Deposit(decimal amount)
{
balance += amount;
Console.WriteLine($"{Thread.CurrentThread.Name} deposited {amount} euro, New Balance: {balance} euro");
}
public void Withdraw(decimal amount)
{
if (balance >= amount)
{
Thread.Sleep(10);
balance -= amount;
Console.WriteLine($"{Thread.CurrentThread.Name} withdrew {amount} euro, New Balance: {balance} euro");
}
else
{
Console.WriteLine($"{Thread.CurrentThread.Name} attempted to withdraw {amount} euro, but insufficient funds!");
}
}
}
}
Skedari Main.cs
using Processes;
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static void Main()
{
ParalelSum paralelSum = new ParalelSum();
}
}
Skedari ParalelSum.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Processes
{
class ParalelSum
{
const int m = 10;
const int n=20;
int sum ;
int[,] matrix = new int[m, n];
int[] rreshti = new int[m];
public ParalelSum()
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
matrix[i, j] = i+1;
}
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
Console.Write(matrix[i, j].ToString() + ",");
}
Console.WriteLine();
}
Console.WriteLine("Calculating the sum sequentialy");
Console.ReadLine();
sum = CalculateSumSequential();
Console.WriteLine("Sequential Sum:" +sum.ToString());
string keyboardPres;
keyboardPres = Console.ReadLine();
sum = 0;
Console.WriteLine("Calculating the sum in paralel");
sum = CalculateSum();
Console.WriteLine("Parallel Sum: "+sum.ToString());
}
public int CalculateSumSequential()
{
int s = 0;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
s = s + matrix[i, j]; //average
}
}
// Console.WriteLine("Sum secuencial: " + s);
return s;
}
public int CalculateSum()
{
Thread[] threads = new Thread[m];
for (int i = 0; i < m; i++)
{
int rowIndex = i;
threads[i] = new Thread(() => RowSum(rowIndex));
threads[i].Start();
}
//make sure all threads are finished
for (int i = 0; i < m; i++)
{
threads[i].Join();
}
for (int i = 0; i < m; i++)
{
sum = sum + rreshti[i];
}
Console.WriteLine("Sum in paralel for each line: " + sum);
return sum;
}
public int RowSum(int row)
{
int s = 0;
for (int j = 0; j < n; j++)
{
s = s + matrix[row, j];
}
rreshti[row]= s;
Console.WriteLine("row=> " + row.ToString()+", sum="+s);
return s;
}
}
}