当前位置:网站首页>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
边栏推荐
- Golang BiliBili live broadcast bullet screen
- HOOK Native API
- Principle, advantages and disadvantages of three operating modes of dc/dc converter under light load
- 1151_ Makefile learning_ Static matching pattern rules in makefile
- Jvxetable sub table record loading completion event
- Note the use of export/import and class inheritance in ES6
- 简单自定义mvc
- [oiclass] chess piece
- How does the trading platform for speculation in spot gold ensure capital security?
- Servlet interview questions
猜你喜欢

简单自定义MVC优化
![[ten minutes] manim installation 2022](/img/54/7b895d785c7866271f06ff49cb20aa.png)
[ten minutes] manim installation 2022
![[QT] QMap使用详解](/img/ee/6e71a3dc5b90d2d1b7f7d3f6b56221.png)
[QT] QMap使用详解
![[wechat applet] how did the conditional rendering list render work?](/img/db/4e79279272b75759cdc8d6f31950f1.png)
[wechat applet] how did the conditional rendering list render work?

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

广播模块代码在autojs4.1.1版本运行正常,但在pro7.0版本上运行报错(未解决)

What are outer chain and inner chain?

图的邻接矩阵存储 C语言实现BFS

QT中foreach的使用

1151_ Makefile learning_ Static matching pattern rules in makefile
随机推荐
[QT] QMap使用详解
C # basic learning (XIII) | breakpoint debugging
发现mariadb数据库时间晚了12个小时
hudi记录
shell统计某个字符串最后一次出现的位置之前的所有字符串
问题记录:fel_lib.c:26:10: fatal error: libusb.h: 没有那个文件或目录
[live broadcast notes 0629] Concurrent Programming II: lock
What is the metauniverse: where are we, where are we going
golang bilibili直播弹幕姬
Differences between comparable and comparator
[practical skills] how to write agile development documents
OP diode limit swing
Simulate activity startup mode in compose
Servlet interview questions
如果辨别我现在交易的外盘股指期货交易平台是否正规安全?
The next change direction of database - cloud native database
Knowledge points of 2022 system integration project management engineer examination: software quality assurance and quality evaluation
If you can tell whether the external stock index futures trading platform I am trading is formal and safe?
How to realize remote collaborative office, keep this strategy!
mysql 主从数据库同步失败的原因