C#知识整理-多线程
进程和线程
进程是一种正在执行的程序。 操作系统使用进程来分隔正在执行的应用程序。 线程是操作系统向其分配处理器时间的基本单元。 每个线程具有计划优先级并维护系统用于保存线程执行暂停时线程上下文的一组结构。 线程上下文包含线程顺畅继续执行所需的全部信息,包括线程的一组 CPU 寄存器和堆栈。 多个线程可在进程上下文中运行。 进程的所有线程共享其虚拟地址空间。 线程可执行任意部分的程序代码,包括其他线程正在执行的部分。
默认情况下,.NET 程序由单个线程(通常称为主线程)启动。 但是,它可以创建其他线程,以与主线程并行或同时执行代码。 这些线程通常称为工作线程。
何时使用多个线程
使用多线程可以提高应用程序的响应能力,并利用多处理器或多核系统提高应用程序吞吐量。
请思考桌面应用程序,其主线程负责用户界面元素并响应用户操作。 使用工作线程执行耗时的操作(这些操作会占用主线程并使用户界面无响应)。 此外,可以使用专用线程,提高网络或设备通信对传入消息或事件的响应能力。
如果程序执行可并行执行的操作,可通过在单独线程中执行这些操作并在多处理器或多核系统中运行程序减少总执行时间。 在此类系统中,使用多线程处理可能会提高吞吐量和响应能力。
线程
通过Thread创建线程
static void Main(string[] args)
{
Console.WriteLine("Test Thread Start");
Thread t1 =new Thread(new ThreadStart(StaticMethod));
t1.Start();
Thread.Sleep(1000);
Console.WriteLine("Test Thread End");
}
static void StaticMethod() {
Console.WriteLine("This is Static Method Start");
Thread.Sleep(2000);
Console.WriteLine("This is Static Method End");
}
// output
Test Thread Start
This is Static Method Start
Test Thread End
This is Static Method End
将数据传递到线程
代码中有两种数据传递方式
- 使用ParameterizedThreadStart
使用ParameterizedThreadStart委托不是传递数据的类型安全方式,因为Thread.Start(Object)方法接受任何对象。
static void StaticMethod1(object text)
{
Console.WriteLine($"This is Static Method with parameter:{text} Start");
Thread.Sleep(2000);
Console.WriteLine($"This is Static Method with parameter:{text} End");
}
Console.WriteLine("Test Thread Start");
Thread t1 = new Thread(StaticMethod1);
t1.Start("test para");
Thread.Sleep(1000);
Console.WriteLine("Test Thread End");
/*
* output
Test Thread Start
Independent task printed 123 lines.
This is Static Method with parameter:test para Start
Test Thread End
This is Static Method with parameter:test para End
*/
- 将线程过程和数据封装在类中
internal class ThreadWithState
{
private string _text;
public ThreadWithState(string text)
{
_text = text;
}
public void ShowMessage()
{
Console.WriteLine($"test thread with state with para:{_text}");
}
}
ThreadWithState tws = new ThreadWithState("test parameter");
Thread t2 = new Thread(new ThreadStart(tws.ShowMessage));
t2.Start();
// output: test thread with state with para:test parameter
- 使用callback delegate
internal class ThreadWithState
{
private string _text;
private ExampleCallback _callback;
public ThreadWithState(string text)
{
_text = text;
}
public ThreadWithState(ExampleCallback callback)
{
_callback = callback;
}
public void ShowMessage()
{
Console.WriteLine($"test thread with state with para:{_text}");
}
public delegate void ExampleCallback(int lineCount);
public static void ResultCallback(int lineCount) {
Console.WriteLine("Independent task printed {0} lines.", lineCount);
}
public void ThreadProc() {
_callback(123);
}
public static void Run() {
ThreadWithState tws = new ThreadWithState(new ExampleCallback(ResultCallback));
Thread t = new Thread(new ThreadStart(tws.ThreadProc));
t.Start();
}
}
ThreadWithState.Run();
// output: Independent task printed 123 lines.
线程池
线程池线程是后台线程。 每个线程均使用默认的堆栈大小,以默认的优先级运行,并且位于多线程单元中。 一旦线程池中的线程完成任务,它将返回到等待线程队列中。 这时开始即可重用它。 通过这种重复使用,应用程序可以避免产生为每个任务创建新线程的开销。
每个进程只有一个线程池。
使用线程池的最简单方法是使用 任务并行库 (TPL)。 默认情况下,TPL 类型(例如Task和Task)使用线程池线程来运行任务。
var t = Task<int>.Run(() => {
// Just loop.
int max = 1000000;
int ctr = 0;
for (ctr = 0; ctr <= max; ctr++)
{
if (ctr == max / 2 && DateTime.Now.Hour <= 12)
{
ctr++;
break;
}
}
Console.WriteLine("Task End");
return ctr;
});
Console.WriteLine("After Task");
Console.WriteLine("Finished {0:N0} iterations.", t.Result);
/*
* output
After Task
Task End
Finished 1,000,001 iterations.
*/

浙公网安备 33010602011771号