C# 多线程
本章将介绍 C# 中的多线程编程,包括线程创建、同步、并行等。
线程基础
创建线程
using System.Threading;
// 创建新线程
Thread thread = new Thread(() =>
{
Console.WriteLine("新线程执行");
});
thread.Start(); // 启动线程
thread.Join(); // 等待线程结束
前台线程和后台线程
// 后台线程(随程序结束而结束)
Thread backgroundThread = new Thread(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine($"后台: {i}");
Thread.Sleep(100);
}
});
backgroundThread.IsBackground = true;
backgroundThread.Start();
// 前台线程(默认)
Thread foregroundThread = new Thread(() =>
{
Console.WriteLine("前台线程");
});
foregroundThread.IsBackground = false;
foregroundThread.Start();
ThreadPool
使用线程池
// 使用线程池执行任务
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("在线程池线程中执行");
});
// 使用 Task(推荐)
Task.Run(() =>
{
Console.WriteLine("使用 Task 在线程池中执行");
});
同步机制
lock 关键字
class Counter
{
private int _count = 0;
private readonly object _lock = new object();
public void Increment()
{
lock (_lock)
{
_count++;
}
}
public int GetCount()
{
lock (_lock)
{
return _count;
}
}
}
Interlocked
int value = 0;
// 原子操作
Interlocked.Increment(ref value); // value++
Interlocked.Decrement(ref value); // value--
Interlocked.Add(ref value, 10); // value += 10
Monitor
object lockObj = new object();
try
{
Monitor.Enter(lockObj);
// 临界区代码
}
finally
{
Monitor.Exit(lockObj);
}
// 或使用 lock 的简化形式
Semaphore(信号量)
// 限制同时访问的线程数
Semaphore semaphore = new Semaphore(3, 3); // 最多3个线程
for (int i = 0; i < 10; i++)
{
new Thread(() =>
{
semaphore.WaitOne(); // 获取信号
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 进入");
Thread.Sleep(1000);
Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 离开");
semaphore.Release(); // 释放信号
}).Start();
}
Mutex
// 跨进程同步
using var mutex = new Mutex(false, "MyMutexName");
mutex.WaitOne(); // 获取
// 临界区
mutex.ReleaseMutex(); // 释放
Task 并行库
Parallel.For 和 Parallel.ForEach
// 并行 for 循环
Parallel.For(0, 100, i =>
{
Console.WriteLine(i);
});
// 并行 foreach
var items = new List<int> { 1, 2, 3, 4, 5 };
Parallel.ForEach(items, item =>
{
Console.WriteLine(item);
});
并行 LINQ
var numbers = Enumerable.Range(1, 1000);
// 顺序执行
var result1 = numbers.Where(n => n % 2 == 0).ToList();
// 并行执行
var result2 = numbers.AsParallel()
.Where(n => n % 2 == 0)
.ToList();
线程本地存储
ThreadLocal<T>
ThreadLocal<int> threadLocal = new ThreadLocal<int>(() =>
{
return Thread.CurrentThread.ManagedThreadId;
});
new Thread(() =>
{
Console.WriteLine(threadLocal.Value); // 不同的值
}).Start();
Console.WriteLine(threadLocal.Value); // 主线程的值
取消操作
CancellationToken
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
if (cts.Token.IsCancellationRequested)
break;
Console.WriteLine(i);
Thread.Sleep(100);
}
}, cts.Token);
// 取消
Thread.Sleep(1000);
cts.Cancel();
小结
- Thread:创建和管理线程
- ThreadPool:线程池管理
- 同步:lock、Monitor、Semaphore、Mutex
- Task:高级异步编程
- Parallel:并行循环
练习
- 创建一个计数器,在多线程环境下正确计数
- 实现一个简单的生产者-消费者队列
- 使用 Parallel.For 实现并行处理
- 实现一个可取消的长时间运行任务