基本概念
进程:
- 进程是操作系统级别的一个基本概念,可以将其简单地理解为“正在运行的程序”。
- 进程是资源调度和分配的基本单位。
- 进程之间是相互独立的。
- 在操作系统级别的管理中,利用Process类可启动、停止本机或远程进程。
线程:
- 从程序实现的角度来讲,将一个进程划分为若干个独立的执行流,每一个执行流均称为一个线程。
- 从硬件实现的角度来讲,可将线程看作是操作系统分配处理器时间的基本执行单元(CPU调度和分配的基本单位)。
- 一个进程中既可以只包含一个线程,也可以同时包含多个线程。
- 线程共享进程的资源
一个车间相当于一个进程,车间内的工人相当于线程
并发执行:
- 宏观上并行,微观上串行。
异步执行:
- 各个线程之间执行时各自运行,无前后关系,无相互等待,执行先后不可知。
进程管理(Process类)
Process类位于System.Diagnostics命名空间下。
对本机:
- 可以启动,终止某个进程
- 可以查看进程相关信息
- 可以查看进程工作状态
对远程计算机:
- 可以查看远程计算机相关信息
- 无法直接启动、终止远程计算机
启动进程
启动进程涉及的方法和属性
- Start方法:启动进程资源并将其与Process组件关联
- StartInfo属性:获取或设置要传递给启动进程的文件名以及启动参数
启动进程涉及的两种方法:
-
先创建Process类的一个实例,并通过StartInfo属性指定要运行的应用程序名称以及传递的参数,然后调用该实例的Start方法启动该进程。此外,如果进程带有图形用户界面,还可以用ProcessWindowStyle枚举指定启动进程时如何显示窗口。可选的枚举值有:Normal(正常窗口),Hidden(隐藏窗口),Minimized(最小化窗口)和Maximized(最大化窗口)。
举例:
-
直接调用Process类提供的Start静态方法启动进程。
举例:Process.Start(“Notpad.exe”);
停止进程
Process类提供的相关方法和属性
-
Kill方法和CloseMainWindow方法,前者用于强行终止进程,后者只是“请求”终止进程。
-
HasExited属性,用于判断启动的进程是否已停止运行。
-
WaitForInputIdle方法,仅适用于具有用户界面的进程,它可以使Process等待关联进程进入空闲状态。
-
WaitForExit方法,设置等待关联进程退出的时间。
-
ExitCode属性和ExitTime属性,ExitCode属性用于获取关联进程终止时指定的值 ,“0”成功,非“0”错误。
ExitTime属性用于获取关联进程退出的时间。
以上两属性只有在HasExited属性为true时才能检测。 -
EnableRaisingEvents属性,用于获取或设置在进程终止时是否应引发Exited事件。(当关联进程终止时引发Exited事件则为true,否则为false)
停止进程的两种方法
-
CloseMainWindow + Close(释放资源): 有图形界面
-
Kill + WaitForExit(等待退出): 所有程序
-
注意:异常处理,调用时最好使用try/catch语句。
获取所有进程信息
- Process类的GetProcesses静态方法用于创建新的Process数组,并将该数组与本地计算机上的所有进程资源相关联。
(1)获取本地计算机的所有进程:
Process[] myProcesses = Process.GetProcesses();
(2)获取远程计算机的所有进程:
Process[] myProcesses =Process.GetProcesses (remoteMachineName);
例如:
Process[] myProcesses =Process.GetProcesses (“192.168.0.1”);
获取指定进程信息
-
Process的GetProcessById静态方法会自动创建Process对象,并将其与本地计算机上的进程相关联,同时将进程Id传递给该Process对象。
-
Process类的有关进程信息的属性:
MachineName属性:获取关联进程正在其上运行的计算机名
MainModule属性:获取关联进程的主模块
Modules属性:获取由关联进程加载的模块
TotalProcessorTime属性:获取进程的总的处理器时间
StartTime属性:获取关联进程的启动时间
WorkingSet64属性:为进程分配的物理内存量(字节数) -
GetProcessesByName静态方法返回一个包含所有关联进程的数组。
获取本地计算机上指定名称的进程
获取远程计算机上指定名称的进程:
参数1是进程名,参数2是远程计算机名称或IP地址
Process[] myProcesses =Process.GetProcessesByName(“远程进程名称”,remoteMachineName);
注意:
进程名称不带扩展名。
可以是任何一个可执行文件
线程管理(Thread类)
相关概念
主线程和辅助线程
前台线程与后台线程
创建和启动线程
-
通过Thread创建一个单独的线程,常用形式为:
Thread t=new Thread(<方法名>); -
线程通过委托来实现的,委托由定义的方法是否带参数而定:
不带参数方法使用ThreadStart委托
带参数方法使用ParameterizedThreadStart委托 -
Thread创建的线程默认为前台线程。
-
线程启动调用该实例的Start方法
//定义无参数的方法
static void MethodA()
{
for (int i = 0; i < 10; i++)
{ Console.WriteLine("i的当前值是:" + i); }
}
//创建线程并启动线程
Thread t1 = new Thread(new ThreadStart(MethodA));
t1.Start();
Thread t2 = new Thread(MethodA);
t2.Start();
//1.定义参数类型为Object的方法
static void MethodC(object obj)
{Console.WriteLine(obj.ToString());}
//2.创建线程
Thread t3 = new Thread(new ParameterizedThreadStart(MethodC));//通过委托启动
Thread t4 = new Thread(MethodC);
//3.传递参数并启动线程
t3.Start("Thread T3");
t4.Start("Thread T4");
线程终止和取消
- 第1种方法是先设置一个修饰符为volatile的布尔型的字段表示是否需要正常结束该线程,称为终止线程。
Volatile关键字:
volatile修饰符表示所声明的字段可以被多个并发执行的线程修改。
volatile修饰符只能包含在类或结构的字段声明中,不能将局部变量声明为volatile。
在布尔型字段的声明中,添加volatile修饰符的方法如下:
public volatile bool shouldStop;
volatile修饰符常用于以下类型:
(1)引用类型。
(2)整型,如sbyte、byte、short、ushort、int、uint、char、float和bool。
(3)具有整数基类型的枚举类型。
(4)已知为引用类型的泛型类型参数。 - 第2种方法是在其他线程中调用Thread实例的Abort方法终止当前线程,该方法的最终效果是强行终止该线程的执行,属于非正常终止的情况,称为取消线程的执行。
休眠线程
调用Thread类提供的静态Sleep方法,可使当前线程暂停一段时间。
注意:
Sleep方法是暂停的是该语句所在的线程,而不是其他线程;并且无法从一个线程中暂停其他的线程。
获取或设置线程的优先级
- 每个线程都具有分配给它的优先级。
- 当线程之间争夺CPU时间片时,CPU是按照线程的优先级进行调度的。
- 创建线程时,默认优先级为Normal。
- 使用下面的方法可为线程赋予较高的优先级:
Thread t1 = new Thread(MethodName);
t1.priority = ThreadPriority.AboveNormal;
线程池(ThreadPool类)
线程池的基本特征
-
托管线程池中的线程都是后台线程。
-
添加到线程池中的任务不一定会立即执行。
-
线程池可自动重用已创建过的线程。一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用,而不是直接销毁它。
-
开发人员可设置线程池的最大线程数。
-
从.NET框架4.0开始,线程池的默认大小由多个因素决定;线程池中的线程都是利用多核处理技术来实现的。
向线程池中添加工作项
线程池多线程编程中的资源同步
同步执行和异步执行
多线程执行过程中的资源同步问题
死锁和争用情况
为了解决死锁问题,C#和.NET框架都提供了多种协调线程同步的方案。
实现资源同步的常用方式
WPF中的多线程编程模型
- 默认情况下,.NET框架都不允许在一个线程中直接访问另一个线程中的控件。
- 为了解决死锁以及异步执行过程中的同步问题,WPF中的每个元素(包括根元素)都有一个Dispatcher属性。