多线程基础-C#
Posted 全栈黑科技
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程基础-C#相关的知识,希望对你有一定的参考价值。
多线程
线程 被定义为程序的执行流。每个线程都定义了一个单独的控制流。如果应用程序涉及到复杂的和耗时的操作,那么将程序分成多个线程执行流往往是有益的,每个线程执行特定的工作。
线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。
为了同时执行多个任务,一个程序可以被划分为更小的线程。
线程生命周期
线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
未启动状态
:当线程实例被创建但Start
方法未被调用时的状况。就绪状态
:当调用了Start
,线程准备好运行并等待 CPU 周期时的状况。不可运行状态
:下面的几种情况下线程是不可运行的:已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞
死亡状态
:当线程已完成执行或已中止时的状况。
主线程
在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。
创建线程
构造函数
#ThreadStart:
#public delegate void ThreadStart();//一个无参数,无返回值的委托
#ParameterizedThreadStart:
#public delegate void ParameterizedThreadStart(object obj);//一个有一个参数、但无返回值的委托
#maxStackSize:线程要使用的最大堆栈大小(以字节为单位);如果为 0 则使用可执行文件的文件头中指定的默认最大堆栈大小。 重要地,对于部分受信任的代码,如果 maxStackSize 大于默认堆栈大小,则将其忽略。 不引发异常。
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start, int maxStackSize);
public Thread(ParameterizedThreadStart start, int maxStackSize);
新建线程
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
}
ThreadStart childref = new ThreadStart(CallToChildThread);
Thread childThread = new Thread(childref);
childThread.Start();
调用 Start
之后,一个线程就进入了 就绪状态
了,等着CPU分配时间片即可。
以上,就是C#的多线程基本知识,如果你只是需要偶尔在程序中使用以下多线程,那么上面的知识就够你启动一个子线程,并将想要执行的任务放到子线程中执行了。
但如果你在线程中大量使用多线程,那么就可能遇到诸如: 线程同步
、 死锁
、 控制线程状态
等需求。
前后线程&后台线程
#获取或设置一个值,该值指示某个线程是否为后台线程。
public bool IsBackground { get; set; }
.Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。 这两者的区别就是:
应用程序必须运行完所有的前台线程才可以退出;
对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
.NET环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。
一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序。
应用程序的主线程以及使用Thread构造的线程都默认为前台线程
线程池线程也就是使用 ThreadPool.QueueUserWorkItem()和Task工厂创建的线程都默认为后台线程
线程执行状态(IsAlive)
#获取一个值,该值指示当前线程的执行状态。
#如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。
public bool IsAlive { get; }
线程状态(ThreadState)
#获取一个值,该值包含当前线程的状态
#System.Threading.ThreadState 值之一(Running、StopRequested、SuspendRequested、Background、Unstarted、Stopped、WaitSleepJoin、Suspended、AbortRequested、Aborted),它指示当前线程的状态。 初始值为 Unstarted。
public ThreadState ThreadState { get; }
线程归属(IsThreadPoolThread)
#获取一个值,该值指示线程是否属于托管线程池。
#如果此线程属于托管线程池,则为 true;否则为 false。
public bool IsThreadPoolThread { get; }
线程标识符(ManagedThreadId)
#获取当前托管线程的唯一标识符。
#一个整数,表示此托管线程的唯一标识符。
public int ManagedThreadId { get; }
线程名字(Name)
#获取或设置线程的名称。
#包含线程名称的字符串,或者如果未设置名称,则为 null。
public string Name { get; set; }
线程优先级(Priority)
#获取或设置一个值,该值指示线程的调度优先级。
#System.Threading.ThreadPriority(Lowest、BelowNormal、Normal、AboveNormal、Highest) 值之一。 默认值为 Normal。
public ThreadPriority Priority { get; set; }
立即执行当前线程,同时阻塞其余线程
#在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止或经过了指定时间为止。
#如果线程已终止,则为 true;如果线程在经过了 millisecondsTimeout 参数指定的时间量后未终止,则为 false。
public void Join();
public bool Join(int millisecondsTimeout);
public bool Join(TimeSpan timeout);
这个方法可以使当前线程立即执行,如果没有参数,则会一直等到当前线程执行结束,如果有参数,则当过时间之后,就会取消这种超级优先级状态。
挂起线程与继续挂起线程
#挂起线程,或者如果线程已挂起,则不起作用。
public void Suspend();
#继续已挂起的线程。
public void Resume();
线程休眠(sleep)
#timeout:设置为线程被阻塞的时间量的 System.TimeSpan。 指定零以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。
public static void Sleep(TimeSpan timeout);
#线程被阻塞的毫秒数。 指定零 (0) 以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。
public static void Sleep(int millisecondsTimeout);
#当前线程暂停 5000 毫秒
int sleepfor = 5000;
Thread.Sleep(sleepfor);
销毁线程(Abort)
Abort() 方法用于销毁线程。
通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。
#在调用此方法的线程上引发 System.Threading.ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
public void Abort(object stateInfo);
public void Abort();
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 Exceptio
以上是关于多线程基础-C#的主要内容,如果未能解决你的问题,请参考以下文章