当前位置:网站首页>C#【高级篇】 C# 多线程
C#【高级篇】 C# 多线程
2022-06-30 03:19:00 【明如正午】
C#【高级篇】 C# 多线程
前言
线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。
线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。
到目前为止我们编写的程序是一个单线程作为应用程序的运行实例的单一的过程运行的。但是,这样子应用程序同时只能执行一个任务。为了同时执行多个任务,它可以被划分为更小的线程。
一、线程生命周期
线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
下面列出了线程生命周期中的各种状态:
未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
不可运行状态:下面的几种情况下线程是不可运行的:
已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞死亡状态:当线程已完成执行或已中止时的状况。
二、主线程
在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。
下面的程序演示了主线程的执行:
using System;
using System.Threading;
namespace MultithreadingApplication
{
class MainThreadProgram
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
运行结果:
This is MainThread
三、创建线程
线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开始子线程的执行。
下面的程序演示了这个概念:
using System;
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
}
static void Main(string[] args)
{
//【写法1】:ThreadStart、Thread都使用
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
//【写法2】只使用Thread。在2.0以后可以像下边这样写,程序会更简单易懂点
//Thread childThread = new Thread(CallToChildThread);
childThread.Start();
Console.ReadKey();
}
}
}
运行结果:
In Main: Creating the Child thread
Child thread starts
特别说明:
下边两种写法的效果是一样的。都是创建一个线程。后者只是 C# 的语法,编译时编译器会自动转换成第一种的形式。ThreadStart 是线程的入口,可以理解为一个函数指针,指向线程将要运行的函数。
Thread childThread = new Thread( new ThreadStart(CallToChildThread));
Thread childThread = new Thread(CallToChildThread);
四、管理线程【Thread.Sleep(1000) 线程暂停1s】
Thread 类提供了各种管理线程的方法。
下面的实例演示了 sleep() 方法的使用,用于在一个特定的时间暂停线程。
using System;
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
// 线程暂停 5000 毫秒
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds",
sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
运行结果:
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
五、销毁线程【Abort()】
Abort() 方法用于销毁线程。
通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。
下面的程序说明了这点:
using System;
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// 计数到 10
for (int counter = 0; counter <= 10; counter++)
{
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
}
catch (ThreadAbortException e)
{
Console.WriteLine("Thread Abort Exception");
}
finally
{
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
// 停止主线程一段时间
Thread.Sleep(2000);
// 现在中止子线程
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
当上面的代码被编译和执行时,它会产生下列结果:
In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception
总结
- 进程和线程的理解:进程(一个程序)、线程(并发时多个分支程序)、主线程(Main)
- 多线程的常见使用:Sleep、Abort、Resume
- 线程池和Task简单了解
补充1【Thread、线程池ThreadPool、Task】
C# 4.0 以后一共有3种创建线程的方式:
- ==Thread ==自己创建的独立的线程, 优先级高,需要使用者自己管理。
- ==ThreadPool ==有 .Net 自己管理, 只需要把需要处理的方法写好, 然后交个.Net Framework, 后续只要方法执行完毕, 则自动退出。
- Task 4.0 以后新增的线程操作方式, 类似 ThreadPool, 但效率测试比ThreadPool略高, Task对多核的支持更为明显,所以在多核的处理器中, Task的优势更为明显。
实例:
using System;
using System.Threading;
namespace ConsoleApp2
{
class Program
{
public static Thread t =null;
static void Main(string[] args)
{
//【01】独立创建线程
t = new Thread(ThreadProcess1);
t.Start(new object());
//【02】线程池
ThreadPool.QueueUserWorkItem(ThreadProcess2, new object());
//【03】Task方式创建线程
System.Threading.Tasks.Task.Factory.StartNew(ThreadProcess3, new object());
Console.ReadLine();
}
private static void ThreadProcess1(object tag)
{
int i = 10;
while (i > 0)
{
Console.WriteLine(string.Format("【01】i:{0} ", i));
Thread.Sleep(10);
i--;
}
Console.WriteLine("【01】线程结束");
//需要手动终止
t.Abort();
}
private static void ThreadProcess2(object tag)
{
int i = 10;
while (i > 0)
{
Console.WriteLine(string.Format("【02】i:{0} ", i));
Thread.Sleep(10);
i--;
}
Console.WriteLine("【02】线程结束");
}
private static void ThreadProcess3(object tag)
{
int i = 10;
while (i > 0)
{
Console.WriteLine(string.Format("【03】i:{0} ", i));
Thread.Sleep(10);
i--;
}
Console.WriteLine("【03】线程结束");
}
}
}
运行结果:
补充2【ThreadStart和ParameterizedThreadStart】
线程函数通过委托传递,可以不带参数,也可以带参数(只能有一个参数),可以用一个类或结构体封装参数:
using System;
using System.Threading;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(TestMethod));
Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));
t1.IsBackground = true;
t2.IsBackground = true;
t1.Start();
t2.Start("hello");
Console.ReadKey();
}
public static void TestMethod()
{
Console.WriteLine("不带参数的线程函数");
}
public static void TestMethod(object data)
{
string datastr = data as string;
Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
}
}
}
运行结果:
不带参数的线程函数
带参数的线程函数,参数为:hello
边栏推荐
- [live broadcast notes 0629] Concurrent Programming II: lock
- QT中foreach的使用
- Compile a DLL without import table
- Mathematical solution of Joseph Ring
- General paging (2)
- Summary of PHP test sites encountered in CTF questions (I)
- 简单自定义MVC优化
- How does the trading platform for speculation in spot gold ensure capital security?
- A GPU approach to particle physics
- Reasons for MySQL master-slave database synchronization failure
猜你喜欢

Redis高并发分布式锁(学习总结)

数据库的下一个变革方向——云原生数据库

The broadcast module code runs normally in autojs4.1.1, but an error is reported in pro7.0 (not resolved)

Principle, advantages and disadvantages of three operating modes of dc/dc converter under light load

自定义MVC的使用

X书6.97版本shield-unidbg调用方式

产品思维 | 无人机快递的未来值得期待吗?

【微信小程序】条件渲染 列表渲染 原来这样用?

Linked list: insert a node in the head
![[practical skills] how to write agile development documents](/img/38/4bab396891ce3cc42595ae8cfd45ce.png)
[practical skills] how to write agile development documents
随机推荐
Principle, advantages and disadvantages of three operating modes of dc/dc converter under light load
Add a custom button to jvxetable
How to realize remote collaborative office, keep this strategy!
Differences between comparable and comparator
Simple custom MVC
unity input system 使用记录(实例版)
DC/DC变换器轻载时三种工作模式的原理及优缺点
Tri rapide, index groupé, recherche de la plus grande valeur K dans les données
Neo4j---性能优化
Stc89c52/90c516rd/89c516rd ADC0832 ADC driver code
HOOK Native API
通用分页(2)
Principle of device driver
&nbsp; Difference from spaces
Which is a good foreign exchange trading platform? Is it safe to have regulated funds?
zabbix 触发器详解
Link garbled escape character
On the role of database tables
On the optimization and use of idea
Auto.js学习笔记16:按项目保存到手机上,不用每次都保存单个js文件,方便调试和打包