Java ใช้ Thread.setDaemon(true) ทำให้ Thread เป็น Daemon Thread (จบเมื่อ Main Thread จบ) ใน C# ใช้ Concept ของ Foreground vs Background Thread
หลักการ C#
- Foreground Thread: Process จะไม่จบจนกว่า Foreground Thread ทั้งหมดจะจบ (Default)
- Background Thread: Process จบได้ทันทีที่ Foreground Thread จบหมด Background Thread จะถูก Terminate ทันที
ตัวอย่าง: สร้าง Background Thread
using System;
using System.Threading;
public class Program
{
public static void Main()
{
// Foreground Thread (Default)
Thread fgThread = new Thread(ForegroundWork);
fgThread.Name = "Foreground";
fgThread.Start();
// Background Thread
Thread bgThread = new Thread(BackgroundWork);
bgThread.Name = "Background";
bgThread.IsBackground = true; // Key Property!
bgThread.Start();
Console.WriteLine("Main thread ending...");
// โปรแกรมจะจบทันที ไม่รอ Background Thread
}
static void ForegroundWork()
{
Thread.Sleep(2000);
Console.WriteLine("Foreground work completed");
}
static void BackgroundWork()
{
Thread.Sleep(5000);
Console.WriteLine("Background work completed"); // จะไม่พิมพ์เพราะ Process จบก่อน
}
}
ผลลัพธ์
Main thread ending...
Foreground work completed
// Background work completed - จะไม่แสดง เพราะ Process Terminated แล้ว
ThreadPool Threads เป็น Background เสมอ
// Task.Run, ThreadPool.QueueUserWorkItem - ทั้งหมดเป็น Background Thread
Task.Run(() => { /* Background */ });
ThreadPool.QueueUserWorkItem(_ => { /* Background */ });
// async/await - Continuation รันบน ThreadPool (Background)
await Task.Delay(1000); // Resumes on Background Thread
ตรวจสอบ Thread Type
Thread.CurrentThread.IsBackground // true/false
// เปลี่ยนระหว่างรันได้ (ก่อน Start เท่านั้น)
Thread t = new Thread(Work);
t.IsBackground = true; // ต้องตั้งก่อน Start()
t.Start();
// หลัง Start แล้วเปลี่ยนได้แต่ไม่แนะนำ
// t.IsBackground = false; // Valid แต่ risky
เมื่อไหร่ควรใช้ Background Thread
- Work ที่ไม่สำคัญถ้าหยุดกลางคัน (Logging, Metrics, Cache Cleanup)
- Fire-and-forget Operations
- Periodic Timer Callbacks
- Worker ที่ Main App ไม่ต้องรอ
เมื่อไหร่ต้องใช้ Foreground Thread
- Critical Work ที่ต้องเสร็จสิ้น (Save Data, Transaction Commit)
- Graceful Shutdown Logic
- Background Thread ที่ต้อง Complete ก่อน Process Exit
Graceful Shutdown Pattern
public class GracefulService
{
private readonly CancellationTokenSource _cts = new();
private readonly Thread _worker;
public GracefulService()
{
_worker = new Thread(DoWork) { IsBackground = false }; // Foreground!
_worker.Start();
}
public void Stop()
{
_cts.Cancel();
_worker.Join(TimeSpan.FromSeconds(5)); // รอจบสูงสุด 5 วิ
}
private void DoWork()
{
while (!_cts.Token.IsCancellationRequested)
{
// Work...
Thread.Sleep(1000);
}
// Cleanup...
}
}