当前位置: 首页 > news >正文

C#多线程Thread、Task

在C#中,线程可以用于完成需要耗费较长时间的操作,而不会阻塞用户界面。一个程序可以有多个线程,每个线程可以并行执行代码。

在C#中,可以使用System.Threading.Thread类来创建和控制线程,使用System.Threading.Mutex类来同步线程。

多线程基本例子

下面是一个C#多线程的简单示例:

using System;
using System.Threading;class Program
{static void Main(string[] args){Thread thread1 = new Thread(new ThreadStart(Work1));Thread thread2 = new Thread(new ThreadStart(Work2));thread1.Start();thread2.Start();thread1.Join();thread2.Join();}static void Work1(){for(int i = 0; i < 5; i++){Console.WriteLine("Work 1 is progressing");Thread.Sleep(1000);}}static void Work2(){for(int i = 0; i < 5; i++){Console.WriteLine("Work 2 is progressing");Thread.Sleep(1000);}}
}

在上面的代码中,我们创建了两个线程,分别执行Work1和Work2方法。我们使用Thread.Start方法启动线程,使用Thread.Join方法等待线程完成。

每个线程会打印出一条消息,然后休眠一秒钟,这个过程会重复五次。因为这两个线程是并行执行的,所以"Work 1 is progressing"和"Work 2 is progressing"消息会交替出现。

需要注意的是,多线程编程是一个复杂的主题,上面只是一个简单的例子。在实际的编程中,你需要处理更复杂的问题,比如线程同步、线程优先级、异常处理等等。

线程同步

在C#中, lock关键字可用于确保一次只有一个线程在执行某个代码块, 这可用于防止多线程同时修改共享的数据结构:

class Program
{static int counter = 0;static object lockObj = new object();static void Main(string[] args){Thread thread1 = new Thread(IncrementCounter);Thread thread2 = new Thread(IncrementCounter);thread1.Start();thread2.Start();thread1.Join();thread2.Join();Console.WriteLine($"Counter is {counter}");}static void IncrementCounter(){for (int i = 0; i < 100000; i++){lock (lockObj){counter++;}}}
}

在这个例子中,lock关键字确保了一次只有一个线程在增加计数器的值。如果没有lock关键字,两个线程可能会同时读取和修改counter变量,从而导致数据的不一致。

线程优先级

在C#中,可以通过Thread.Priority属性来设置线程的优先级。

Thread thread = new Thread(() => 
{// Do Something
});thread.Priority = ThreadPriority.Highest;  // 设置线程的优先级为最高thread.Start();

请注意,线程优先级应该谨慎使用,因为它可能会导致线程饿死,也就是高优先级的线程持续运行,而低优先级的线程永远得不到运行的机会。

异常处理

在线程中运行的代码可能会抛出异常,需要正确地处理这些异常。下面是一个处理线程异常的例子:

Thread thread = new Thread(() =>
{try{// Do Something}catch (Exception ex){Console.WriteLine($"Caught exception: {ex.Message}");}
});thread.Start();

在这个例子中,我们在线程的代码块中使用try/catch语句来捕获和处理异常。

Task

在C#中,ThreadTask都可以用来实现多线程编程,但它们之间存在一些重要的区别。

Thread:

  • Thread是一个较低级别的方式来处理多线程,需要手动创建和管理线程。
  • Thread提供了对操作系统线程的直接控制,这意味着你可以设置线程的优先级、线程的状态等。
  • Thread不支持返回值和取消操作。
  • Thread需要手动处理异常。

Task:

  • Task是一个更高级别,更抽象的概念,它使用线程池来管理线程,无需用户手动创建和管理线程。
  • Task可以返回结果,并且支持取消操作。
  • Task可以自动处理异常,并且可以在多个Task之间传播异常。
  • Task可以更容易地实现异步操作。

下面是两个例子,分别展示了如何使用ThreadTask

Thread 例子:

class Program
{static void Main(string[] args){Thread thread = new Thread(() => {Console.WriteLine("Hello from thread");});thread.Start();thread.Join();}
}

Task 例子:

class Program
{static void Main(string[] args){Task task = Task.Run(() => {Console.WriteLine("Hello from task");});task.Wait();}
}

在实际编程中,如果可能的话,推荐使用Task,因为它提供了更多的功能,而且更容易使用。

Task其它用法

Task有很多高级用法,例如你可以使用Task来实现异步编程,还可以使用ContinueWith方法来链接多个任务。以下是一些例子:

使用Task实现异步编程

在C#中,asyncawait关键字可以与Task一起使用,以实现异步编程。这可以避免阻塞主线程,提高程序的响应性。

static async Task Main(string[] args)
{Task<int> task = CalculateSumAsync(10, 20);// Do other things while CalculateSumAsync is running in the backgroundint result = await task;Console.WriteLine($"The result is {result}");
}static async Task<int> CalculateSumAsync(int a, int b)
{// Simulate a long-running operationawait Task.Delay(1000);return a + b;
}

使用ContinueWith链接多个任务

ContinueWith方法可以用来链接多个任务,当一个任务完成后,另一个任务会自动开始。

Task<int> task1 = Task.Run(() => 
{// Do some workreturn 1;
});Task<int> task2 = task1.ContinueWith(t => 
{// This task starts after task1 completesreturn t.Result + 1;
});task2.Wait();
Console.WriteLine($"The result is {task2.Result}");  // Output: The result is 2

使用Task.WhenAll等待多个任务完成

Task.WhenAll方法可以用来等待多个任务都完成。

Task task1 = Task.Run(() => 
{// Do some work
});Task task2 = Task.Run(() => 
{// Do some work
});await Task.WhenAll(task1, task2);
Console.WriteLine("All tasks completed");

以上就是Task的一些高级用法,Task提供了很多功能,使得多线程编程变得更加简单和高效。

http://www.lryc.cn/news/232366.html

相关文章:

  • Qt QWebSocket实现JS调用C++
  • Android Matrix的使用详解(通过矩阵获取到图片缩放比例和角度)
  • 【Spring】bean的生命周期
  • C#运算符重载
  • 【L2GD】: 无环局部梯度下降
  • 2023-11-14 LeetCode每日一题(阈值距离内邻居最少的城市)
  • AdServices归因和iAd归因集成
  • 关于 内部类 你了解多少?(详解!!)
  • CNVD-2021-09650:锐捷NBR路由器(guestIsUp.php)RCE漏洞复现 [附POC]
  • 如何在Docker部署Draw.io绘图工具并远程访问
  • Android APK打包的过程主要步骤
  • 吃透 Spring 系列—MVC部分
  • Java面试题(每天10题)-------连载(32)
  • HDP集群Kafka开启SASLPLAINTEXT安全认证
  • 判断上颌下颌的stl模型坐标轴是否正常
  • C/C++---------------LeetCode第1189. “气球” 的最大数量
  • Arthas(阿尔萨斯)--(三)
  • 《变形监测与数据处理》笔记/期末复习资料(择期补充更新)
  • Linux:进程替换和知识整合
  • React组件在什么情况下会重新渲染
  • 云ES容灾方案
  • Golang 中的 Context 包
  • nginx服务器
  • 电脑常用快捷键
  • 吴恩达《机器学习》8-3->8-4:模型表示I、模型表示II
  • 数据结构-二叉树力扣题
  • node 第十八天 中间件express-session实现会话密钥
  • 【机器学习基础】机器学习入门(1)
  • 赶快来!程序员接单必须知道的六大注意事项!!!
  • 【C++】日期类实现,与日期计算相关OJ题