什么是多线程编程

什么是线程(Thread)

线程是运行在进程上下文中的逻辑流,每个线程都拥有自己的线程上下文,包括唯一的线程ID,通用目的寄存器等。多个线程运行在同一进程的上下文中,共享这个进程的虚拟地址空间。

可以基于线程创建并发逻辑流,实现并发编程。

在C#中,可以使用Thread.CurrentThread.ManagedThreadId显示出当前线程ID,使用 Task.Run Method 将耗时任务放到线程池中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
var task1 = Task.Run(async () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
});
var task2 = Task.Run(async () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(2000);
});

Task.WaitAll(new Task[] { task1, task2 });
// output: 1 5 9

什么是线程安全

线程安全指在多线程环境中,公用变量能够被正确处理。

C#中使用 Parallel.For Method 编写并行代码:

1
2
3
4
5
6
7
var count = 0;
Parallel.For(0, 10000, t =>
{
count++;
});
Console.WriteLine(count);
// output: 6463

可以使用 lock 来确保单个线程具有对线的独占访问权。

1
2
3
4
5
6
7
8
9
10
11
var lockObject = new object();
var count = 0;
Parallel.For(0, 10000, t =>
{
lock (lockObject)
{
count++;
}
});
Console.WriteLine(count);
// output: 10000

此外,.Net中也提供了多个线程安全集合类 System.Collections.Concurrent Namespace

为什么会有线程安全问题

代码中count++并非原子操作,大致分为3条指令:

  1. 读:内存》寄存器
  2. 执行:寄存器 +1
  3. 写:寄存器》内存

如果多个线程同时执行,则可能发生:1读,2读,1执行,1写,2执行,2写。则执行后,count=count+1。