1. 获取本机可用的逻辑内核数
StringBuilder sb = new StringBuilder();
sb.Append($“本机处理器数: {Environment.ProcessorCount}”);
sb.Append($“\n是否为64位操作系统:{Environment.Is64BitOperatingSystem}”);
sb.Append($“\n当前进程是否为64位进程: {Environment.Is64BitProcess}”);
sb.Append($“\n当前进程占用的物理内存量: {Environment.WorkingSet/1024/1024} M”);
Console.WriteLine(sb.ToString());
2.进程管理Process类
using System.Diagnostics;
(1)启动进程
Process p = new Process();
p.StartInfo.FileName = “NotePad.exe”;
p.StartInfo.Arguments = “Mytest.txt”;
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.Start();
(2)停止进程
Kill( )方法
终止没有图形界面进程的唯一方法。 非正常终止
异步执行,再调用WaitForExit()方法等待进程退出,或者检查HasExited属性确得进程是否已经退出。
CloseMainWindow( ) 方法
向进程的主窗口发送关闭消息来关闭进程,其行为与用户在界面单击关闭按钮效果相同
Process[] ps = Process.GetProcessesByName(“NotePad”);//Process.GetProcesses()
foreach (var p in ps)
{
p.CloseMainWindow();
if(!p.HasExited)
{
p.Kill();
}
}
WaitForInputIdle方法,仅适用于具体有用户界面的进程,它可以使Process等待关联进程进入空闲状态。达到空闲返回true,否则返回false
WitForExit 方法, 设置等待关联进程退出时间,并在该段时间结束前或该进程退出前,阻止当前线程执行。
ExitCode属性用于获取关联进程终止时指定的值,0表示成功退出,非零表示错误编号。
ExitTime属性, 属性用于获取关联进程退出时间。 这2个属性只能在HasExited 属性为true时才能检测。
EnableRaisingEvrnts 属性, 用于设置或获取在进程终止时是否引发Exited 事件。默认false, 如果关联进程的进程终止时引发Exited事件则为true.
(3)获取所有进程
//本机所有进程
Process[] ps = Process.GetProcesses();
//远程主机:IP或远程计算机名称
Process[] rps = Process.GetProcesses(“192.168.1.102”);
(4)获取指定进程
GetProcessById( ), GetProcessByName()
Process[] ps = Process.GetProcessesByName(“进程名称”);
Process[] ps = Process.GetProcessesByName(“进程名称”,“Server”);
3. 线程管理 Thread类
Thread类 用于管理单独的线程,包括创建线程,启动线程,终止线程和合并线程以及线程休眠等。
(1) 主线程和辅助线程
应用程序创建的默认线程,主线程。 一个进程,除了主线程之外的其它线程都称为辅助线程。
(2) 前台线程和后台线程
后台线程不会影响进程的终止,而前台线程则会影响进程的终止。
某个进程的所有前台线程都终止,后台线程也会立即停止,则不管是否完成工作。
Thread类创建的线程都默认时前台线程,在托管线程池执行的线程默认都是后台线程。
IsBackground属性: 获取或设置一个值,该值指示某个线程是否后台执行。
IsThreadPoolThread属性: 获取一个值,该值指示线程是否在托管线程池中执行。true 表示线程在托管池中执行,否则false
为了使主线程能及时对用户操作的界面进行响应,可将辅助线程做“后台”任务来执行,即后台线程。IsBackground=true,目的是不让该线程影响UI操作。
(3) 创建线程
创建一个独立的线程:
Thread th= new Thread(<方法名称>);
创建一个线程th, 并自动通过相应的委托执行“<方法名>”指定的方法。
方法是否带参数:
Thread t1= new Thread(new ThreadStart(Method1));
等价: Thread t1= new Thread(Method1);
Thread t2= new Thread(new ParameterizedThreadStart(Method2));
等价: Thread t2= new Thread(Method2);
设置为后台线程: t1.IsBackground=true
启动创建的线程
t1.Start();
t2.Start(“xxx”);
注意 带参数的方法的参数必须定义为Object,传入方法后组类型转换
Thread t2 = new Thread(new ParameterizedThreadStart(M2));
t2.Start(12);
private static void M2(object x)
{
for (int i = 0; i < (int)x; i++) { Thread.Sleep(12); Console.WriteLine($"M2: {i.ToString()}"); }
}
终止或取消线程
方式1: 先设置一个修饰符 volatile 的布尔型的字段表示是否需要正常结束该线程,称为终止线程。
public volatile bool shouldStop;
线程中循环判断该布尔值,以确定是否退出该线程。在其它线程中可以修改该布尔值,通知是否希望终止该线程。
方式2: 在其它线程中调用线程实例的Abort方法终止当前线程。强行终止线程的执行,非正常终止。
休眠线程
暂停一段时间 Thread.Sleep(1000);//暂停1秒
设置线程或获取线程的优先级
t1.priority=ThreadPriority.AboveNormal;
4.线程池类 ThreadPool
线程池总是后台异步处理,不占用主线程,也不会延迟线程周后续请求的处理。
(1) 线程池的基本特征
(2) 向线程池中添加工作项
ThreadPool.QueueUserWorkItem方法向线程池中添加工作项
ThreadPool.QueueUserWorkItem(new WaitCallback(Method1));
5.多线程编程中的资源同步
(1) 同步执行和异步执行
(2) 多线程执行过程中的资源同步问题
– 防止多个线程同时访问某些资源时出现死锁和争用情况
(3)死锁和争用情况
– 死锁典型例子是2个线程都停止响应,并且都等待对方完成,从而导致任何一个线程都不能继续执行。
– 争用情况是当程序的结果取决于两个或多个线程中的哪一个先达到某一特定代码块时出现的一种错误Bug. 每次运行的结果都不可预知。
(4) 实现资源同步的常用方式
加锁或原子操作
用Volatile修饰符锁定公共或私有字段
利用该修饰符可直接访问内存中的字段,而不是将字段缓存在某个处理器的寄存器中。优点是所有处理器都可以直接访问该字段的最新值。
private static volatile bool isStop = false;
Public static bool IsStop
{
get { return isStop;} set { isStop= value; }
}
用InterLocked类提供的静态方法锁定局部变量
System.Threading.Interlocked类通过加锁和解锁提供了原子级别的静态操作,并对执行过程中的某个局部变量进行操作,采用这种方法实现同步。
int num;
Interlocked.Increment(ref num);
Interlocked.Decrement(ref num);
用lock语句锁定代码块。
该语句确保当一个线程完成执行代码块前,不会被其它线程中断。被锁定的代码块称为临界区域。
private List d= new List();
lock(d)
{
// 对List操作
}
当代码块中的语句执行完成,再自动解除该锁
如果锁定代码段中包含多个需要同步的字段或多个局部变量,可先定义一个私有字段lockedObj,通过一次性锁定该私有字段实现多个变量的同步操作。
private Object lockedObj= new Object();
lock(lockObj)
{
// .....
}
lock 对象可以是任意类型,但不允许锁定类型本身。
也不允许声明为Public,否则将会使lock语句无法控制。从而引发一序列问题。
临界区代码一般不宜太多。