跳到主要内容

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();

小结

  1. Thread:创建和管理线程
  2. ThreadPool:线程池管理
  3. 同步:lock、Monitor、Semaphore、Mutex
  4. Task:高级异步编程
  5. Parallel:并行循环

练习

  1. 创建一个计数器,在多线程环境下正确计数
  2. 实现一个简单的生产者-消费者队列
  3. 使用 Parallel.For 实现并行处理
  4. 实现一个可取消的长时间运行任务