C# 多线程编程全面指南:从基础到高级实践

article/2025/7/22 13:37:56

在现代软件开发中,多线程编程已成为提升应用程序性能的关键技术。C# 作为.NET平台的主力语言,提供了丰富的多线程处理机制。本文将全面介绍C#中的多线程编程技术,从基础概念到高级应用,帮助开发者掌握这一重要技能。

一、多线程基础概念

1.1 什么是线程

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源。

1.2 为什么需要多线程

  • 提高响应性:在GUI应用中,主线程保持响应,后台线程处理耗时操作

  • 充分利用多核CPU:现代CPU多为多核设计,多线程可以并行执行

  • 提高吞吐量:服务器应用可以同时处理多个客户端请求

  • 简化建模:某些问题天然适合多线程模型(如仿真系统)

1.3 线程与进程的区别

特性进程线程
资源占用独立内存空间共享进程内存
创建开销
通信方式进程间通信(IPC)共享内存
独立性一个进程崩溃不影响其他一个线程崩溃可能影响整个进程

二、C#线程基础操作

2.1 创建和启动线程

using System.Threading;// 基本线程创建
Thread basicThread = new Thread(SimpleWork);
basicThread.Start();void SimpleWork()
{Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}正在执行简单工作");Thread.Sleep(1000); // 模拟工作Console.WriteLine("工作完成");
}

2.2 参数传递

// 带参数的线程
Thread paramThread = new Thread(ParameterizedWork);
paramThread.Start("自定义参数");void ParameterizedWork(object data)
{Console.WriteLine($"接收到参数: {data}");// 处理工作...
}

2.3 线程状态管理

线程有以下几种状态:

  • Unstarted

  • Running

  • WaitSleepJoin

  • Stopped

Thread stateThread = new Thread(() => {Console.WriteLine("线程即将进入休眠");Thread.Sleep(2000); // 进入WaitSleepJoin状态Console.WriteLine("线程唤醒");
});
Console.WriteLine($"初始状态: {stateThread.ThreadState}");
stateThread.Start();
Thread.Sleep(500);
Console.WriteLine($"运行中状态: {stateThread.ThreadState}");
stateThread.Join(); // 等待线程结束
Console.WriteLine($"结束状态: {stateThread.ThreadState}");

三、高级线程管理

3.1 线程池技术

.NET提供了线程池来优化线程管理:

// 使用线程池
for (int i = 0; i < 10; i++)
{ThreadPool.QueueUserWorkItem(state => {Console.WriteLine($"线程池线程 {Thread.CurrentThread.ManagedThreadId} 处理任务 {state}");Thread.Sleep(500);}, i);
}

线程池特点

  • 自动管理线程生命周期

  • 限制最大线程数防止资源耗尽

  • 重用线程减少创建开销

3.2 Task类:现代多线程编程

using System.Threading.Tasks;// 基本Task使用
Task.Run(() => {Console.WriteLine("Task在后台运行");
});// 带返回值的Task
Task<int> calculateTask = Task.Run(() => {Thread.Sleep(1000);return 42;
});
Console.WriteLine($"计算结果: {calculateTask.Result}");// 任务链
Task.Run(() => 10).ContinueWith(t => t.Result * 2).ContinueWith(t => Console.WriteLine($"最终结果: {t.Result}"));

四、异步编程模型(async/await)

4.1 基本用法

async Task<string> FetchDataAsync()
{Console.WriteLine("开始获取数据...");await Task.Delay(2000); // 模拟网络请求Console.WriteLine("数据获取完成");return "数据内容";
}async Task ProcessDataAsync()
{string data = await FetchDataAsync();Console.WriteLine($"处理数据: {data}");
}// 调用
await ProcessDataAsync();

4.2 异常处理

async Task SafeOperationAsync()
{try{await PossibleFailingOperationAsync();}catch (Exception ex){Console.WriteLine($"操作失败: {ex.Message}");}
}async Task PossibleFailingOperationAsync()
{await Task.Delay(500);throw new InvalidOperationException("模拟错误");
}

五、线程同步与资源共享

5.1 锁机制

private readonly object _lockObj = new object();
private int _sharedCounter = 0;void IncrementCounter()
{lock (_lockObj){_sharedCounter++;Console.WriteLine($"计数器: {_sharedCounter}");}
}// 多线程测试
Parallel.For(0, 10, i => IncrementCounter());

5.2 高级同步原语

Mutex示例

using var mutex = new Mutex(false, "Global\\MyAppMutex");try
{mutex.WaitOne();// 临界区代码
}
finally
{mutex.ReleaseMutex();
}

SemaphoreSlim示例

SemaphoreSlim semaphore = new SemaphoreSlim(3); // 允许3个并发async Task AccessResourceAsync(int id)
{Console.WriteLine($"任务 {id} 等待访问");await semaphore.WaitAsync();try{Console.WriteLine($"任务 {id} 获得访问权");await Task.Delay(1000); // 模拟工作}finally{semaphore.Release();Console.WriteLine($"任务 {id} 释放访问权");}
}// 启动多个任务
var tasks = Enumerable.Range(1, 10).Select(i => AccessResourceAsync(i)).ToArray();
await Task.WhenAll(tasks);

六、并发集合

.NET提供了线程安全的集合类:

using System.Collections.Concurrent;// 并发字典
var concurrentDict = new ConcurrentDictionary<string, int>();
concurrentDict.TryAdd("key1", 1);
concurrentDict.AddOrUpdate("key1", 1, (k, v) => v + 1);// 并发队列
var concurrentQueue = new ConcurrentQueue<int>();
concurrentQueue.Enqueue(1);
if (concurrentQueue.TryDequeue(out int value))
{Console.WriteLine($"出队值: {value}");
}// 阻塞集合
var blockingCollection = new BlockingCollection<int>(boundedCapacity: 5);
Task producer = Task.Run(() => {for (int i = 0; i < 10; i++){blockingCollection.Add(i);Console.WriteLine($"生产: {i}");}blockingCollection.CompleteAdding();
});Task consumer = Task.Run(() => {foreach (int item in blockingCollection.GetConsumingEnumerable()){Console.WriteLine($"消费: {item}");Thread.Sleep(200);}
});await Task.WhenAll(producer, consumer);

七、取消操作模式

async Task LongRunningOperationAsync(CancellationToken token)
{for (int i = 0; i < 100; i++){token.ThrowIfCancellationRequested();Console.WriteLine($"进度: {i}%");await Task.Delay(200, token);}
}var cts = new CancellationTokenSource();
try
{// 5秒后自动取消cts.CancelAfter(5000);await LongRunningOperationAsync(cts.Token);
}
catch (OperationCanceledException)
{Console.WriteLine("操作被取消");
}

八、最佳实践与常见陷阱

8.1 最佳实践

  1. 优先选择Task而非Thread:Task提供了更高级的抽象和更好的性能

  2. 合理使用async/await:保持UI响应性,避免死锁

  3. 最小化锁范围:只锁定必要的代码段

  4. 避免共享状态:尽可能使用不可变对象和局部变量

  5. 使用取消令牌:提供优雅的取消机制

8.2 常见陷阱

  1. 死锁:不正确的锁顺序导致

    // 错误示例
    lock (A)
    {lock (B){// 代码}
    }
    // 另一个线程
    lock (B)
    {lock (A){// 代码}
    }
  2. 线程饥饿:某些线程长期得不到执行

  3. 竞态条件:未正确同步导致的不确定行为

  4. 上下文切换开销:过多线程导致性能下降

九、性能考量

  1. 线程创建成本:创建线程是昂贵的操作,优先使用线程池

  2. 内存使用:每个线程需要分配栈空间(默认1MB)

  3. CPU缓存:频繁的线程切换会导致缓存失效

  4. 测量而非猜测:使用性能分析工具(如Visual Studio Profiler)

十、实际应用案例

10.1 并行数据处理

async Task ProcessLargeDataAsync()
{var data = Enumerable.Range(1, 1000000).ToList();// 并行处理var results = await Task.Run(() => data.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount).Where(x => x % 2 == 0).Select(x => HeavyComputation(x)).ToList());Console.WriteLine($"处理完成,结果数: {results.Count}");
}int HeavyComputation(int input)
{Thread.Sleep(1); // 模拟耗时计算return input * 2;
}

10.2 高并发Web请求

async Task DownloadMultiplePagesAsync()
{var urls = new[] { "url1", "url2", "url3" };var downloadTasks = urls.Select(url => DownloadPageAsync(url)).ToList();while (downloadTasks.Count > 0){var completedTask = await Task.WhenAny(downloadTasks);downloadTasks.Remove(completedTask);try{string content = await completedTask;Console.WriteLine($"下载完成,长度: {content.Length}");}catch (Exception ex){Console.WriteLine($"下载失败: {ex.Message}");}}
}async Task<string> DownloadPageAsync(string url)
{using var client = new HttpClient();return await client.GetStringAsync(url);
}

结语

C#多线程编程是一个强大但需要谨慎使用的工具。通过本文的介绍,您应该已经了解了从基础线程操作到高级异步编程的各个方面。记住,多线程编程的核心原则是:正确性第一,性能第二。只有在确保线程安全的前提下,才应该考虑性能优化。

随着.NET平台的不断发展,async/await模式已经成为处理并发问题的首选方式。它不仅能简化代码,还能有效避免许多传统多线程编程中的陷阱。希望本文能帮助您在C#多线程编程的道路上更加得心应手。

 


http://www.hkcw.cn/article/MyHfEPkANl.shtml

相关文章

PASCAL VOC数据集/AI标注/算法训练推理EasyAML如何实现“数据不出域”的本地化AI标注训练

在当今数字化转型的大潮中&#xff0c;众多企业对AI视觉技术的需求日益增长。无论是制造业的产品质量检测、物流行业的货物识别与车辆管理&#xff0c;还是安防领域的视频监控与分析&#xff0c;AI视觉技术的应用场景广泛且多样。然而&#xff0c;在实际应用过程中&#xff0c;…

Linux系统中的shell脚本基础知识

1.shell脚本基础&#xff1a;shell脚本是文本的一种&#xff0c;属于可以运行的文本&#xff0c;shell脚本的内容是由逻辑和数据组成的。 2.shell脚本意义&#xff1a;shell脚本语言是实现Linux/unix系统管理及自动化运维所必备的重要工具。 常见shell种类&#xff1a;Bourne …

C++修炼:位图和布隆过滤器

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 1、引言 在计算机科学…

贾冰瘦脱相 压力给到沈腾了 减肥热潮席卷娱乐圈

5月31日,演员贾冰的妻子发布了一段视频,祝福大家端午节快乐,并配文“从此我家多了个瘦子”。从两人合影中可以看出,贾冰明显瘦了很多。评论区里很多人询问他如何瘦下来的,甚至有人表示他瘦得有些认不出来了。贾冰妻子回复说,主要是通过少吃(一天一顿)和运动达到的。贾冰…

AdaCtrl:自适应可控Reasoning,可降10~90%推理长度!!

摘要&#xff1a;现代大型推理模型通过运用复杂的推理策略展示了令人印象深刻的解决问题能力。然而&#xff0c;它们常常难以平衡效率和有效性&#xff0c;经常为简单问题生成不必要的冗长推理链。在本研究中&#xff0c;我们提出了AdaCtrl&#xff0c;这是一个新颖的框架&…

格式工厂 FormatFactory v5.20.便携版 ——多功能媒体文件转换工具 长期更新

—————【下 载 地 址】——————— 【​本章下载一】&#xff1a;https://pan.xunlei.com/s/VORWF3Q7D0eCVV06LHbzheD-A1?pwdjikz# 【​本章下载二】&#xff1a;https://pan.quark.cn/s/8ee59ed83658 【百款黑科技】&#xff1a;https://ucnygalh6wle.feishu.cn/wiki/…

贾冰瘦到脱相 网友:压力给到沈腾 减肥风潮席卷娱乐圈

5月31日,演员贾冰的妻子发布了一段视频,祝福大家端午节快乐,并配文“从此我家多了个瘦子”。在两人合影中,贾冰明显瘦了很多。评论区里大家都在问他是如何瘦下来的,甚至有人觉得他瘦得都快认不出来了。对此,贾冰妻子回复说,主要是通过少吃(一天一顿)和运动来减肥的。贾…

多地机关食堂端午向社会开放 节日共享美食

端午假期,全国多地政府机关食堂面向社会公众开放。重庆市荣昌区政府机关食堂在5月31日中午如约向游客开放,首日吸引了超过3000名游客前来体验。该食堂特别推出了61元的“六一”家庭套餐,包括荣昌卤鹅、黄凉粉等特色菜品,并新增了粽子和儿童喜欢的薯条、鸡腿、鸡块等小吃,让…

vscode实用配置

前端开发安装插件&#xff1a; 1.可以更好看的显示文件图标 2.用户快速打开文件 使用步骤&#xff1a;在html文件下右键点击 open with live server 即可 刷力扣&#xff1a; 安装这个插件 还需要安装node.js即可

武夷山耗资千万建不锈钢天池?假 AI谣言混淆视听

近日,武夷山市委网信办工作人员在日常网络舆情巡查中发现,有网民在某网络平台上发布信息,称无人机航拍到武夷山耗资千万修建的“不锈钢天池”。经武夷山国家公园福建管理局核实,该文章为不实信息。文中提到的“不锈钢天池”并不位于武夷山国家公园范围内,而是位于重庆武陵…

战国足前印尼集训着重练习定位球 强化任意球战术

印尼队在巴厘岛的集训中加强了定位球战术的训练。此前客场与国足的交手中,印尼队曾利用任意球完成破门。这次集训,克鲁伊维特招入了维克里、萨尤里兄弟、利利帕利和普特拉等前锋,这些球员速度快、脚下技术好,能够丰富球队的进攻套路,并在前场积极逼抢,阻滞国足的防守反击…

网页自动化部署(webhook方法)

实现步骤&#xff1a; 宝塔安装宝塔WebHook 2.5插件。 github 上配置网页仓库&#xff08;或可在服务器的网页根目录clone&#xff09;。 配置宝塔WebHook 2.5 添加hook脚本&#xff1b; 编辑添加syncJC脚本&#xff1b; #!/bin/bash # 定义网站根目录 WEBROOT"/www…

Redis持久化

文章目录 持久化1、RDB1&#xff09;触发机制2&#xff09;bgsave命令的运行流程3&#xff09;RDB文件的处理4&#xff09;RDB的优缺点 2、AOF1&#xff09;开启AOF2&#xff09;AOF工作流程3&#xff09;AOF同步策略4&#xff09;重写机制5&#xff09;重写机制的运行流程 持久…

循环流化床锅炉关键技术设计与优化路径

摘要 循环流化床锅炉&#xff08;CFB&#xff09;作为高效清洁燃烧技术的代表&#xff0c;在燃煤发电、生物质利用等领域具有显著优势。本文从设计原理出发&#xff0c;详细分析物料循环系统、燃烧室结构、受热面布置等核心设计要素&#xff0c;并提出针对不同燃料特性的优化方…

PyTorch-Transforms的使用(二)

对图像进行处理 安装open cv ctrlP 看用法 ToTensor的使用 常见的Transforms 归一化的图片 两个长度为三的数组&#xff0c;分别表示三个通道的平均值和标准差 Resize&#xff08;&#xff09; Compose&#xff08;&#xff09; 合并执行功能&#xff0c;输入进去一个列表&a…

【萌笔趣棋】网页五子棋项目测试报告

目录 一.项目介绍 &#xff08;一&#xff09;项目简介 &#xff08;二&#xff09;功能介绍 &#xff08;三&#xff09;页面展示 1.注册页面 2.登录页面 3.游戏大厅页面 4.游戏房间页面&#xff08;对战&#xff09; 二.功能测试 &#xff08;一&#xff09;出现的…

乌克兰袭击俄轰炸机基地画面曝光 大胆军事行动震动俄乌

乌克兰官员周日宣布,乌克兰军队对俄罗斯境内深处的多个军用机场进行了大规模无人机袭击。这些机场是用于进行空袭的战略轰炸机基地,这次行动被认为是自俄乌冲突爆发以来乌克兰军队最大胆的一次军事行动。此次代号为“蛛网”的袭击行动经过一年半的准备。乌克兰无人机的目标包…

卡友护送青藏线司机骨灰回家 爱心跨越2400公里

河南46岁的卡车司机常志荣在青海五道梁地区因高原缺氧离世,家中还有六个孩子需要抚养。为了省下一罐氧气的钱,他在出发前只购买了一罐氧气。五道梁地区海拔4665米,含氧量不足海平面的一半,自然环境极其恶劣。得知消息后,多名卡车司机自费远赴2000多公里护送常志荣的骨灰及…

北京全市上汛责任人名单公示 防汛抗旱任务明确

今日天气早晨有轻雾,白天晴转多云,西部北部有分散性阵雨或雷阵雨,北风一级转三四级,阵风六七级,最高气温31℃;夜间多云转晴,北风三级左右转一级,最低气温15℃。白天阵风明显,户外注意防风。尾号限行无昨日8时北京全市上汛,为做好2025年防汛抗旱工作,切实履行防汛抗旱…

Oracle递归/树状查询

目录 1.递归与LEVEL简介 2.往子项找 3.往父项找 4.练习题 练习1&#xff1a;找出BLAKE的直系下属有哪些&#xff1f; 练习2 5.递归的其他应用——生成连续的数字或日期 1.递归与LEVEL简介 递归&#xff1a;从顶层到下一层级&#xff0c;一层一层递归去找。 递归里…