Multithreading - potatoscript/csharp GitHub Wiki
🥔 Multithreading in C# 🥔
🎯 What is Multithreading?
Imagine you are running a potato factory 🏭 where you:
- 🥔 Peel the potatoes.
- 🔪 Cut the potatoes.
- 🍳 Fry the potatoes.
- 🎁 Pack the French fries.
If you had only one worker, they would do everything one by one. It would take forever to finish! ⏳
✅ But if you hire 4 workers, they can do these tasks at the same time:
- Worker 1: Peels the potatoes 🥔.
- Worker 2: Cuts the potatoes 🔪.
- Worker 3: Fries the potatoes 🍳.
- Worker 4: Packs the fries 🎁.
Multithreading works just like that! It allows you to run multiple tasks at the same time, which makes your program faster and more efficient. ⚡🥔
🧠 How Does Multithreading Work?
A thread is like a worker who performs a task in the potato factory. 🥔👨🔧
✅ Single-threaded program: Only one worker processes everything.
✅ Multi-threaded program: Multiple workers handle tasks at the same time.
⚡ Why Use Multithreading?
Without multithreading:
- 🐢 Everything happens one by one.
- ⏰ It takes a lot of time.
With multithreading:
- 🚀 Multiple tasks happen simultaneously.
- 🎉 Your program runs faster and can handle multiple operations easily.
🥔 Basic Syntax of Multithreading in C#
To create a thread in C#, you use:
Thread
class fromSystem.Threading
.Start()
to begin the thread.Join()
to wait for the thread to finish.
🎁 Simple Multithreading Example
using System;
using System.Threading;
class Program
{
static void Main()
{
// Create two threads for different tasks
Thread peelThread = new Thread(PeelPotatoes);
Thread cutThread = new Thread(CutPotatoes);
// Start the threads
peelThread.Start();
cutThread.Start();
// Wait for both threads to complete
peelThread.Join();
cutThread.Join();
Console.WriteLine("🍽️ All tasks finished!");
}
static void PeelPotatoes()
{
Console.WriteLine("🥔 Peeling potatoes...");
Thread.Sleep(2000); // Simulate 2 seconds of work
Console.WriteLine("✅ Done peeling.");
}
static void CutPotatoes()
{
Console.WriteLine("🔪 Cutting potatoes...");
Thread.Sleep(2000); // Simulate 2 seconds of work
Console.WriteLine("✅ Done cutting.");
}
}
✅ Explanation:
Thread
– Creates a new thread.Start()
– Begins the thread.Join()
– Waits for the thread to finish.
🎁 Output:
🥔 Peeling potatoes...
🔪 Cutting potatoes...
✅ Done peeling.
✅ Done cutting.
🍽️ All tasks finished!
✅ Benefit: Tasks happen simultaneously! No waiting! 🎉
🥔 Multithreading with Parameters
You can pass parameters to a thread using ParameterizedThreadStart
.
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ParameterizedThreadStart(PeelPotatoes));
thread.Start(5); // Passing 5 potatoes to peel
thread.Join();
Console.WriteLine("🍽️ All potatoes peeled!");
}
static void PeelPotatoes(object numPotatoes)
{
int count = (int)numPotatoes;
for (int i = 1; i <= count; i++)
{
Console.WriteLine($"🥔 Peeling potato {i}...");
Thread.Sleep(1000); // Simulate 1 second per potato
}
Console.WriteLine("✅ All potatoes peeled!");
}
}
✅ Explanation:
ParameterizedThreadStart
– Allows passing parameters to the thread.thread.Start(5)
– Starts the thread with5
potatoes.
🎁 Output:
🥔 Peeling potato 1...
🥔 Peeling potato 2...
🥔 Peeling potato 3...
🥔 Peeling potato 4...
🥔 Peeling potato 5...
✅ All potatoes peeled!
🍽️ All potatoes peeled!
🥔 Using Lambda Expressions with Threads
For simpler tasks, you can use lambda expressions to define thread behavior.
using System;
using System.Threading;
class Program
{
static void Main()
{
// Create thread using lambda expression
Thread thread = new Thread(() =>
{
Console.WriteLine("🥔 Peeling potatoes...");
Thread.Sleep(2000);
Console.WriteLine("✅ Done peeling.");
});
thread.Start();
thread.Join();
Console.WriteLine("🍽️ All tasks done!");
}
}
✅ Explanation:
()=> { ... }
– Defines the task for the thread.Start()
– Starts the thread.
🎁 Output:
🥔 Peeling potatoes...
✅ Done peeling.
🍽️ All tasks done!
🥔 Thread Safety and Locks
When multiple threads try to access the same data, it can cause conflicts and errors. This is called a race condition. 🏁🥔
✅ To prevent this, we use locks.
🔐 Using lock to Prevent Race Conditions
using System;
using System.Threading;
class Program
{
static int potatoCount = 0;
static object lockObject = new object();
static void Main()
{
Thread thread1 = new Thread(AddPotatoes);
Thread thread2 = new Thread(AddPotatoes);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"🥔 Total potatoes processed: {potatoCount}");
}
static void AddPotatoes()
{
for (int i = 0; i < 5; i++)
{
lock (lockObject) // Lock to prevent conflicts
{
potatoCount++;
Console.WriteLine($"🥔 Potato added! Total: {potatoCount}");
}
Thread.Sleep(500);
}
}
}
✅ Explanation:
lock (lockObject)
– Ensures only one thread modifiespotatoCount
at a time.potatoCount++
– Safely adds to the potato count.
🎁 Output:
🥔 Potato added! Total: 1
🥔 Potato added! Total: 2
🥔 Potato added! Total: 3
🥔 Potato added! Total: 4
🥔 Potato added! Total: 5
🥔 Potato added! Total: 6
🥔 Potato added! Total: 7
🥔 Potato added! Total: 8
🥔 Potato added! Total: 9
🥔 Potato added! Total: 10
🥔 Total potatoes processed: 10
✅ Benefit: No conflict between threads! 🎉
🥔 Thread Pooling in C#
When you need to run many short tasks, using Thread Pool is faster than creating new threads manually.
using System;
using System.Threading;
class Program
{
static void Main()
{
Console.WriteLine("🥔 Starting Thread Pool...");
for (int i = 1; i <= 5; i++)
{
ThreadPool.QueueUserWorkItem(ProcessPotato, i);
}
Thread.Sleep(3000); // Wait for all threads to finish
Console.WriteLine("🍽️ All tasks done!");
}
static void ProcessPotato(object state)
{
int potatoNum = (int)state;
Console.WriteLine($"🥔 Processing potato {potatoNum}...");
Thread.Sleep(1000);
Console.WriteLine($"✅ Potato {potatoNum} done!");
}
}
✅ Explanation:
ThreadPool.QueueUserWorkItem()
– Queues a task to be executed by available threads in the thread pool.
🎁 Output:
🥔 Starting Thread Pool...
🥔 Processing potato 1...
🥔 Processing potato 2...
🥔 Processing potato 3...
🥔 Processing potato 4...
🥔 Processing potato 5...
✅ Potato 1 done!
✅ Potato 2 done!
✅ Potato 3 done!
✅ Potato 4 done!
✅ Potato 5 done!
🍽️ All tasks done!
🥔 Best Practices for Multithreading
- ✅ Use Thread Pool: For short tasks.
- ⚡ Avoid Excessive Threads: Too many threads slow down the system.
- 🔐 Use Locks: Prevent conflicts in shared data.
- ⏰ Avoid Thread.Sleep(): Use
Task.Delay()
in async code. - 📚 Use
Task
andasync/await
for better performance.
🥔 Summary of Multithreading
🌟 Feature | 📝 Description |
---|---|
⏳ Thread Creation | Create multiple threads for tasks. |
🏎️ Faster Execution | Run tasks simultaneously. |
🔐 Thread Safety | Use lock to prevent data conflicts. |
⚡ Thread Pool | Use thread pool for short tasks. |
🥔 Parameterized Threads | Pass data to threads. |