C# 线程手册 第二章 .net 中的线程 创建一个线程
2012年01月12日
我们将写一个简单的例子。对于我们为什么使用一个新的线程来说这不是一个好例子但是它将我们稍后要提到的复杂问题都去掉了。创建一个simple_thread.cs文件并把下面的代码粘贴进去: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { class SimpleThread { void SimpleMethod() { int i = 5; int x = 10; int result = i * x; Console.WriteLine("This code calculated the value " + result.ToString() + " from thread ID: " + Thread.CurrentThread.ManagedThreadId); } static void Main(string[] args) { //Calling the method from our current thread. SimpleThread simpleThread = new SimpleThread(); simpleThread.SimpleMethod(); //Calling the method on a new thread. ThreadStart ts = new ThreadStart(simpleThread.SimpleMethod); Thread t = new Thread(ts); t.Start(); Console.ReadLine(); } } }
现在保存,编译然后运行。你的输出会类似下面的结果:
我们继续研究这个小例子以确定我们确实了解发生了什么。由于我们已经知道线程相关功能都被封装到System.Threading命名空间中去了。所以我们必须首先将这个命名空间导入到我们的工程。一旦命名空间导入了,我们就可以在主线程中和新的工作线程中创建一个方法。我们使用SimpleMethod()方法: void SimpleMethod() { int i = 5; int x = 10; int result = i * x; Console.WriteLine("This code calculated the value " + result.ToString() + " from thread ID: " + Thread.CurrentThread.ManagedThreadId); }
我们使用第一章介绍的AppDomain来找出正在运行哪个线程。这个方法不论何时执行,都显示一个哪个线程在执行操作的报告。
我们的程序入口是Main()方法。首先会调用与主方法运行在同一个线程的SimpleMethod()方法。下一步很重要:我们第一次可以看看如何创建一个线程。在C#中创建一个线程之前,我们首先必须创建一个ThreadStart委托实例。委托是一个面向对象的类型安全的程序指针。由于我们将要告诉一个线程执行什么方法,所以我们必须将程序指针传递给线程的构造函数。我们的程序中会描述这个: ThreadStart ts = new ThreadStart(simpleThread.SimpleMethod);
需要注意这里的方法名是不加括号的;它只是简单的使用方法名。当我们创建完ThreadStart委托,我们接下来可以创建我们的线程来执行代码。Thread唯一的构造函数将ThreadStart委托的实例作为参数。我们来看看代码中是如何表示的: Thread t = new Thread(ts);
我们定义了一个变量t作为新线程的名字。线程类的构造函数将ThreadStart委托作为它唯一的参数。
下一行代码是Thread对象的Start()方法。通过调用我们传给构造函数的ThreadStart委托,我们开始一个新执行线程。最后通过Console.ReadLine()来等待我们的键盘输入: t.Start(); Console.ReadLine();
额,我们已经创建了一个线程,但是仅仅这些还不能帮助我们洞悉线程的力量。事实上除了显示不同的线程ID我们还没有做别的。为了在一个更加真实的应用场景中看一下如何使用同样的线程代码,我们将创建另外一个模拟后台有一个长时间运行线程同时前台有另外一个线程的程序。在一个新文件do_something_thread.cs中创建一个新的控制台应用程序: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { public class DoSomethingThread { static void WorkerMethod() { for (int i = 1; i
由于上面的这段代码并没有介绍新技术所以咱们就略过。然而,需要注意在两个线程在分享执行时间。任意一个线程都会被阻塞直到另外一个执行完。每个线程都被分配一个很短的时间来执行。在一个线程用完自己的执行时间后,下一个线程会在自己的时间片内开始执行。两个线程互相交替直到执行结束。事实上,不是只有我们的两个线程在交替并共享时间片。我们不是仅在我们的程序中交换时间片。现实是,我们与当前计算机中运行的很多线程共享执行时间。 ThreadStart 和 执行分支
我们再看一下之前提到的ThreadStart委托。我们可以使用这些委托做一些有意思的事情。举个现实世界中的例子。假设你想在一个用户运行某个程序时做一些后台的例行任务。不同的角色运行同样程序会在后台执行不同的例行任务。例如,假设一个管理员运行了一个程序,你想在后台运行一个线程来收集报告数据并对数据进行格式化处理(做一个报表)。后台线程会在报表准备好的时候通知管理员。你可能不想对普通用户也提供类似管理员的这种报表服务。这就是ThreadStart的面向对象功能有用的地方。
现在看一些简单的例子。我们不会准确地模拟上面描述的场景,但是我们将演示如何依据ThreadStart定义的特定标准处理不同情况。创建一个应用程序以及一个新文件ThreadStartBranching.cs, 然后把下面代码复制到新文件中: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { public class ThreadStartBranching { enum UserClass { ClassAdmin, ClassUser, } static void AdminMethod() { Console.WriteLine("Admin Method"); } static void UserMethod() { Console.WriteLine("User Method"); } static void ExecuteFor(UserClass uc) { ThreadStart ts; ThreadStart tsAdmin = new ThreadStart(AdminMethod); ThreadStart tsUser = new ThreadStart(UserMethod); if (uc == UserClass.ClassAdmin) { ts = tsAdmin; } else { ts = tsUser; } Thread t = new Thread(ts); t.Start(); } static void Main() { //execute in the context of an admin user ExecuteFor(UserClass.ClassAdmin); //execute in the context of a regular user ExecuteFor(UserClass.ClassUser); Console.ReadLine(); } } }
代码的输出结果:
我们将描述从上面代码中得到的一些重点。首先,你将注意到我们创建了可能执行程序的用户集合: enum UserClass { ClassAdmin, ClassUser, }
接下来我们创建了两个方法:AdminMethod() 和 UserMethod(). 这两个方法会执行一系列指令并依据类型的不同而得到不同结果。我们这里只想确定它们已经运行了所以就简单地把结果输出到控制台: static void AdminMethod() { Console.WriteLine("Admin Method"); } static void UserMethod() { Console.WriteLine("User Method"); }
下一个你要注意的是在Execute()方法内我们声明了一个叫做ts的变量作为一个ThreadStart类,但是没有使用New关键字创建一个新实例。我们然后创建了两个指向上面创建的不同方法的ThreadStart对象: ThreadStart ts; ThreadStart tsAdmin = new ThreadStart(AdminMethod); ThreadStart tsUser = new ThreadStart(UserMethod);
所以,现在我们有了两个ThreadStart对象和一个可以存储ThreadStart实例的变量。然后我们使用If语句来让我们的代码形成分支并根据我们的商业逻辑为空的变量设置ThreadStart实例: if (uc == UserClass.ClassAdmin) { ts = tsAdmin; } else { ts = tsUser; }
最后,我们向我们的线程构造函数传递动态赋值的ThreadStart委托来创建一个线程,然后开始执行: Thread t = new Thread(ts); t.Start();
线程属性和方法
我们在本章的开头曾说过线程类有很多属性和方法。我们承诺过使用System.Threading命名空间来控制线程执行会变得更加简单。到目前为止,我们所做的就是创建线程然后启动它们。
让我们再看一两个线程类的成员;Sleep()方法和IsAlive属性。我们在第一章曾说过一个线程可能会在一段时间内进入睡眠状态直到发生了时钟中断。让一个线程进入睡眠状态和调用静态Sleep()方法一样简单。我们也说过我们可以确定一个线程的状态。在下面的例子中我们将使用IsAlive属性来确定一个线程是否已经执行完,使用Sleep()方法来暂停一个线程的执行。在下面的这段代码中我们将演示如何使用这两个成员: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { public class ThreadState { static void WorkerFunction() { string ThreadState; for (int i = 1; i
让我们看一下我们首先使用新概念的Main()方法,我们创建了一个线程并将我们想让委托执行的函数传递过去: Thread t = new Thread(new ThreadStart(WorkerFunction)); t.Start();
注意不是创建一个变量来存储我们的ThreadStart类,而是创建一个临时变量并把它作为我们线程构造函数的参数。通常来说,由于处理器会进行线程切换所以我们的Main()方法会与新线程一起执行。然后我们使用新创建线程的IsAlive属性来看它是否在执行。并将持续检测这个变量。当工作线程活动时,主线程将持续睡眠200毫秒,然后醒来并再次测试工作线程是否是活动的: while (t.IsAlive) { Console.WriteLine("Still waiting, I'm going back to sleep."); Thread.Sleep(200); }
下面我们想看看代码中使用了两次的ThreadState属性。ThreadState实际上是一个返回枚举类型的属性。枚举值会告诉你线程状态。我们可以使用上一个例子中的if语句来判断这个属性也可以将它转换成字符串格式并输出到控制台: ThreadState = t.ThreadState.ToString(); Console.WriteLine("He's finally done! Thread state is: " + ThreadState); Console.ReadLine();
剩下是一些不需要看的标准代码。要注意一些重要内容。首先是我们告诉一个线程睡眠一段时间以便于把执行时间放弃给其他线程。使用Thread对象的Sleep()方法-将我们想要线程睡眠的时间值传递进去。其次,我们可以使用IsAlive属性来判断线程是否执行完。最后,我们可以使用线程实例的ThreadState属性来确定他们的精确状态。
线程优先级
线程优先级确定每个线程相对其他线程的优先级。ThreadPriority枚举定义了线程优先级的值。总共有以下几个:
1. Highest
2. AboveNormal
3. Normal
4. BelowNormal
5. Lowest
当运行时创建一个线程且没有给它设置任何优先级时,线程会采用默认的Normal 优先级。然而,这不能通过ThreadPriority枚举改变。在看一下有关线程优先级的例子之前,我们来看看什么是线程优先级。我们创建一个简单的线程例子来显示线程的名字,状态以及优先级信息,thread_priority.cs: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { public class ThreadPriority { public static Thread worker; static void Main() { Console.WriteLine("Entering void Main()"); worker = new Thread(new ThreadStart(FindPriority)); //Let's give a name to the thread. worker.Name = "FindPriority() Thread"; worker.Start(); Console.WriteLine("Exiting void Main()"); Console.ReadLine(); } public static void FindPriority() { Console.WriteLine("Name: " + worker.Name); Console.WriteLine("State: " + worker.ThreadState.ToString()); Console.WriteLine("Priority: " + worker.Priority.ToString()); } } }
输出结果如下:
我们知道工作线程优先级是Normal。我们加一个新线程,然后以不同优先级调用同样方法。thread_priority2.cs: using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace SimpleThread { public class Thread_priority2 { public static Thread worker; public static Thread worker2; static void Main() { Console.WriteLine("Entering void Main()"); worker = new Thread(new ThreadStart(FindPriority)); worker2 = new Thread(new ThreadStart(FindPriority2)); //Let's give a name to the thread worker.Name = "FindPriority() Thread"; worker2.Name = "FindPriority() Thread 2"; //Give the new thread object the highest priority worker2.Priority = ThreadPriority.Highest; worker.Start(); worker2.Start(); Console.WriteLine("Exiting void Main()"); Console.ReadLine(); } public static void FindPriority() { Console.WriteLine("Name: " + worker.Name); Console.WriteLine("State: " + worker.ThreadState.ToString()); Console.WriteLine("Priority: " + worker.Priority.ToString()); } public static void FindPriority2() { Console.WriteLine("Name: " + worker2.Name); Console.WriteLine("State: " + worker2.ThreadState.ToString()); Console.WriteLine("Priority: " + worker2.Priority.ToString()); } } }
输出结果类似下面:
线程基于使用Priority属性设置的优先级来调度执行。每个操作系统对不同优先级的线程处理都不同且每个操作系统都可以改变线程优先级。
我们的应用程序没有办法禁止操作系统改变由程序员设置的线程优先级,这是因为操作系统是所有线程的管理者且它知道何时、如何调度它们。例如,线程优先级可以由操作系统基于以下几个因素动态修改,比如用户输入等系统事件有较高优先级而内存紧缺将触发垃圾回收机制。
下一篇我们将会介绍时钟和回调…
发表评论
-
周线选
2012-01-20 11:11 824周线选 21小时前 大盘30日线起码走平 周 ... -
2011年全国大学生数学建模竞赛c题个人分析
2012-01-20 11:11 9532011年全国大学生数学建模竞赛c题个人分析 2011年09 ... -
冲刺一答案
2012-01-20 11:11 550冲刺一答案 23小时前 冲刺押题卷一 政治冲刺试卷 ... -
单元过关----捷达学校中级《财务管理》测试题(6)
2012-01-20 11:10 1813单元过关----捷达学校中 ... -
【转】 oracle exception总结(读书笔记)
2012-01-19 16:01 649【转】 oracle exception总结(读书笔记) 2 ... -
php编译mysql configure: error: mysql configure failed. Please check config.log for more information
2012-01-19 16:01 1286php编译mysql configure: error: my ... -
Error in symeqn called by dstmak. Please send data to your ANSYS Technical S
2012-01-19 16:01 1787Error in symeqn called by dstma ... -
linux设备模型深探(2)【转】
2012-01-19 16:01 829linux设备模型深探(2)【转】 2011年12月07日 ... -
C#实现Xml日志记录文件的最优方案
2012-01-19 16:01 997C#实现Xml日志记录文件的最优方案 2012年01月05日 ... -
JavaScript跨域总结与解决办法
2012-01-17 05:53 516JavaScript跨域总结与解决 ... -
关于fckeditor在服务器上无法上传图片的问题
2012-01-17 05:53 963关于fckeditor在服务器上无法上传图片的问题 2010 ... -
FCKEditor 2.6.3 ASP.NET 图片上传 停留在进度条问题解决
2012-01-17 05:53 783FCKEditor 2.6.3 ASP.NET 图片上传 停留 ... -
寻访福建最美乡村之 南安蔡浅古大厝
2012-01-16 04:40 1187寻访福建最美乡村之 ... -
专项训练十七
2012-01-16 04:39 677专项训练十七 2012年01 ...
相关推荐
1. **线程创建**:C#中创建线程主要有两种方式,一是通过`System.Threading.Thread`类,创建`Thread`对象并调用`Start`方法启动;二是通过实现`System.Threading.ThreadStart`或`System.Action`委托,利用`new ...
C#面试题 包括 ADO.net 多线程等 C#面试题 包括 ADO.net 多线程等 C#面试题 包括 ADO.net 多线程等 C#面试题 包括 ADO.net 多线程等 C#面试题 包括 ADO.net 多线程等
.net C#线程超时的解决方案,使用的时候在被调线程入口调用一下这个方法就可以。更多详细代码见附件 Report.RegisterThread(Report.GetCurrentWin32ThreadID(),Thread.CurrentThread); #region 获取当取线程的...
C#.net同步异步SOCKET通讯和多线程总结 C#.net同步异步SOCKET通讯和多线程总结是...套接字通信是指服务器端和客户端之间的连接及数据传送,多线程编程是指在一个程序中同时运行多个线程,以提高程序的效率和响应速度。
c#线程参考手册 c#线程参考手册 c#线程参考手册
C#线程参考手册 多线程 高级编程处理
在C#(ASP.NET)开发中,多线程是一个重要的概念,它允许应用程序同时执行多个任务,从而提高程序的效率和响应性。本示例主要介绍了如何使用`System.Threading.Thread`类来创建和管理多线程,以进行并行计算。 首先,...
C#线程参考手册 第1章 定义线程 第2章 .NET中的线程 第3章 使用线程 第4章 线程设计规范 第5章 线程应用程序的伸缩 第6章 调试与跟踪线程 第7章 联网与线程
《C#线程参考手册》是一本专注于C#编程中多线程技术的权威指南,旨在帮助开发者深入理解和熟练运用线程技术。线程是现代应用程序中的重要概念,尤其是在并发和并行处理方面,它是多任务环境下的核心元素。本手册通过...
《C#线程手册》第七章的源代码深入解析 在C#编程中,线程是并发执行任务的基础,它们允许程序同时处理多个任务,从而提高应用的性能和响应性。第七章的源码深入探讨了C#中的线程管理和多线程编程,这是理解和优化多...
MySQL提供了一个名为`MySql.Data.MySqlClient`的.NET数据提供者,通过这个库,我们可以方便地在C#中进行数据库操作。以下是一个简单的连接示例: ```csharp using MySql.Data.MySqlClient; // 创建数据库连接 ...
本篇将深入探讨C#线程相关的知识,并基于描述中的“C#线程参考手册”相关代码进行讨论。 1. **线程创建与启动** 在C#中,我们可以使用`Thread`类来创建新线程。创建一个新线程的基本步骤包括实例化`Thread`对象并...
C# 创建线程 控制和查看线程的运行情况 京华志&精华志出品 希望大家互相学习,互相进步 支持CSDN 支持微软 主要包括C# ASP.NET SQLDBA 源码 毕业设计 开题报告 答辩PPT等
而《C#线程参考手册》这本书,尽管年代稍显久远,但似乎仍然是一个全面了解C#线程使用的不错选择。 为了帮助读者更好地理解C#线程编程,以下列举了一些关键知识点: 1. 线程创建与启动: - 使用System.Threading...
最近收集的VB.Net-C#多线程Thread-代理委托delegate编程。文章列表: c#.net多线程同步.txt C#WebBrowser页面与WinForm交互技巧一.txt C#多线程编程-多细全.txt C#多线程编程简单实例.txt C#多线程窗体控件安全访问....
在.NET框架中,C#语言提供了强大的多线程支持,使得开发者可以充分利用现代多核处理器的优势,实现并行处理和高效编程。以下是对标题和描述中提到的C#.NET多线程实例进行的详细解析: 1. **多线程基本使用**: 多...
本手册将深入探讨C#中的线程概念、创建与管理线程的方法,以及如何优化线程的使用。 一、线程基础知识 线程是操作系统分配CPU时间的基本单位,一个进程可以包含一个或多个线程。在C#中,我们可以使用System....
在.NET框架中,C#语言提供了强大的多线程支持,使得开发者可以同时执行多个任务,提升程序的执行效率。本文将深入探讨C#.NET多线程的基本使用、线程同步和互斥等关键知识点,结合六个实例进行详细解析。 1. **多...