1、多线程
进程类是指 Process 类,该类所在的命名空间是 System.Diagnostics。线程状态控制的方法包括暂停线程 (Sleep)、中断线程 (Interrupt)、挂起线程 (Suspend)、唤醒线程 (Resume)、终止线程 (Abort)。
Process[] processes = Process.GetProcesses();
foreach(Process p in processes)
{
richTextBox1.Text = richTextBox1.Text + p.ProcessName + "\r\n";
}
//设置进程名称
Process p = new Process();
p.StartInfo.FileName = ProcessName;
//启动进程
p.Start();
2、在使用 Thread 类的构造方法创建其实例时,需要用到 ThreadStart 委托或者 ParameterizedThreadStart 委托创建 Thread 类的实例。
Thread.Sleep(1000);
ThreadStart 委托只能用于无返回值、无参数的方法,ParameterizedThreadStart 委托则可以用于带参数的方法。
ThreadStart ts = new ThreadStart( 方法名 );
Thread t = new Thread(ts);
t.Priority = ThreadPriority.Lowest;
t.Start();
ParameterizedThreadStart pts=new ParameterizedThreadStart( 方法名 );
Thread t=new Thread(pts);
ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven);
Thread t = new Thread(pts);
t.Start(10) void PrintEven(Object n)
ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven);
ParameterTest pt = new ParameterTest(1, 10);
Thread t = new Thread(pts);
t.Start(pt);
3、实现线程同步可以使用 lock 关键字和 Monitor 类、Mutex 类来解决。
lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程。
lock(object)
{
//临界区代码
}
Monitor 类的命名空间是 System.Threading
使用 Monitor 类锁定资源的代码如下。
Monitor.Enter(object);
try
{
//临界区代码
}
finally
{
Monitor.Exit(object);
}
Mutex 类也是用于线程同步操作的类,例如,当多个线程同时访问一个资源时保证一次只能有一个线程访问资源。
WaitOne() 方法用于等待资源被释放, ReleaseMutex() 方法用于释放资源。
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
using System.Threading; //Thread类
using System.Diagnostics; // Process类
namespace Threat
{
class Program
{
/// <summary>
/// 模拟发红包,当剩余五个时线程终止
/// </summary>
private static int count = 10;
private static void GiveRedEnvelop()
{
while (count > 0)
{
count--;
if (count == 4)
{
//终止当前线程
Console.WriteLine("红包暂停发放!");
// Thread.CurrentThread.Abort(); //调用此方法通常会终止线程。
}
Console.WriteLine("剩余 {0} 个红包", count);
}
}
private static Mutex mutex = new Mutex(); // 互斥
public static void PakingSpace(object num)
{
if (mutex.WaitOne())
{
try
{
Console.WriteLine("车牌号{0}的车驶入!", num);
Thread.Sleep(1000);
}
finally
{
Console.WriteLine("车牌号{0}的车离开!", num);
mutex.ReleaseMutex();
}
}
}
static void Main(string[] args)
{
#region 进程相关
/*
Process[] processes = Process.GetProcesses(); //获取所有进程
foreach (Process p in processes)
{
Console.WriteLine(p.ProcessName + "\r\n");
}
//创建Process 类的对象 //启动某个进程
Process p1 = new Process();
Console.Write("输入要启用的进程的名字:");
string proceeName = Console.ReadLine();
//设置进程名称
p1.StartInfo.FileName = Convert.ToString(proceeName);
//启动进程
p1.Start();
//关闭进程
Console.Write("输入要关闭的进程的名字:");
string proceeNameStop = Console.ReadLine();
Process[] processesstop = Process.GetProcessesByName(proceeNameStop);
//判断是否存在指定进程名称的进程
if (processesstop.Length > 0)
{
try
{
foreach (Process p in processesstop)
{
//判断进程是否处于运行状态
if (!p.HasExited)
{
//关闭进程
p.Kill();
Console.WriteLine(p.ProcessName + "已关闭!");
//获取所有进程信息
processes = Process.GetProcesses();
}
}
}
catch
{
Console.WriteLine("该进程无法关闭!");
}
}*/
#endregion
#region 线程初识
/*
// 第一个线程,打印偶数
//ThreadStart 委托只能用于无返回值、无参数的方法,ParameterizedThreadStart 委托则可以用于带参数的方法。具体实例看mutex部分
ThreadStart ts1 = new ThreadStart(PrintEven); // 使用ThreadStart委托为PrintEvent方法创建ThreadStart委托的实例
Thread t1 = new Thread(ts1); //创建Thread类的实例
优先级的值通过 ThreadPriority 枚举类型来设置,从低到高分别为Lowest、BelowNormal、Normal、AboveNormal、Highest。默认的优先级是 Normal。
每次输出的结果也不是固定的。通过优先级是不能控制线程中的先后执行顺序的,只能是优先级高的线程优先执行的次数多而已。
t1.Priority = ThreadPriority.Highest;
线程状态控制的方法包括暂停线程(Sleep)、中断线程(Interrupt)、挂起线程(Suspend)、唤醒线程(Resume)、终止线程(Abort)。
//使用暂停线程(Sleep) 的方法让打印奇数和打印偶数的线程交替执行,
//第二个线程,打印奇数
ThreadStart ts2 = new ThreadStart(PrintOld);
Thread t2 = new Thread(ts2);
t2.Priority = ThreadPriority.Highest;
t1.Start(); // 通过Start方法启动线程并调用PrintEven()方法
t2.Start(); // 通过Start方法启动线程并调用PrintOld()方法 两个线程由于没有对线程的执行顺序和操作做控制,所以运行该程序每次打印的值的顺序是不一样的。
//使用 ParameterizedThreadStart 创建进程,首先需要创建 ParameterizedThreadStart委托调用带参数的方法时,方法中的参数只能是 object 类型并且只能含有一个参数。
//传递一个参数的线程
ParameterizedThreadStart pts = new ParameterizedThreadStart(PrintEven1);
Thread t = new Thread(pts);
t.Start(20);
t.Priority = ThreadPriority.Highest;
//引用多个参数的方法
ParameterizedThreadStart pts3 = new ParameterizedThreadStart(PrintEven2);
ParameterTest pt3 = new ParameterTest(1, 30);
Thread t3 = new Thread(pts3);
t3.Start(pt3);
*/
#endregion
#region 发红包线程模拟
ThreadStart hb = new ThreadStart(GiveRedEnvelop);
Thread h = new Thread(hb);
h.Start();
使用 Thread 对象的 IsBackground 属性来判断线程是否为后台线程。,在应用程序运行结束后,后台线程即使没有运行完也会结束,前台线程必须等待自身线程运行结束后才会结束。
if (h.IsBackground == false)
{
Console.WriteLine("该线程不是后台线程!");
h.IsBackground = true;
}
else
{
Console.WriteLine("该线程是后台线程!");
}
#endregion
#region Lock、Monitor、Mutex
实现线程同步可以使用 lock 关键字和 Monitor 类、Mutex 类来解决
// 1、lock:给线程加锁,保证线程同步.线程同步的方法是将线程资源共享,允许控制每次执行一个线程,并交替执行每个线程。
/*通过 lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程。
先执行奇数线程,再执行偶数线程。*/
Program program = new Program();
ThreadStart ts4 = new ThreadStart(program.LockPrintOdd);
Thread t4 = new Thread(ts4);
t4.Name = "打印奇数的线程";
t4.Start();
ThreadStart ts5 = new ThreadStart(program.LockPrintEven);
Thread t5 = new Thread(ts5);
t5.Name = "打印偶数的线程";
t5.Start();
//2、Monitor
/*Monitor 类的用法虽然比 lock 关键字复杂,但其能添加等待获得锁定的超时值,这样就不会无限期等待获得对象锁。
使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。
使用 TryEnter() 方法设置获得对象锁的时间的代码如下。
Monitor.TryEnter(object, 毫秒数);该方法能在指定的毫秒数内结束线程,这样能避免线程之间的死锁现象
Monitor 类中的 Wait() 方法让线程等待一定的时间,使用 Pulse() 方法通知处于等待状态的线程*/
ThreadStart ts6 = new ThreadStart(program.MonitorPrintOdd);
Thread t6 = new Thread(ts4);
t6.Name = "打印奇数的线程";
t6.Start();
ThreadStart ts7 = new ThreadStart(program.MonitorPrintEven);
Thread t7 = new Thread(ts7);
t7.Name = "打印偶数的线程";
t7.Start();
//3、Mutex 类也是用于线程同步操作的类
/*当多个线程同时访问一个资源时保证一次只能有一个线程访问资源。
在 Mutex 类中,WaitOne() 方法用于等待资源被释放, ReleaseMutex() 方法用于释放资源。
WaitOne() 方法在等待 ReleaseMutex() 方法执行后才会结束。*/
ParameterizedThreadStart tc = new ParameterizedThreadStart(PakingSpace);
Thread t8 = new Thread(tc);
t8.Start("冀A12345");
Thread t9 = new Thread(tc);
t9.Start("京A00000");
#endregion
}
/// <summary>
/// 打印0~10中的偶数的方法
/// </summary>
private static void PrintEven()
{
for (int i = 0; i <= 10; i = i + 2)
{
//让线程休眠1S
//Thread.Sleep(1000);
Console.WriteLine(i);
}
}
/// <summary>
/// 打印1~10中的奇数的方法
/// </summary>
private static void PrintOld()
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
}
/// <summary>
/// 传递一个参数的打印偶数的方法
/// </summary>
/// <param name="n"></param>
private static void PrintEven1(object n)
{
for (int i = 0; i <= (int)n; i = i + 2)
{
Console.WriteLine(i);
}
}
/// <summary>
/// 传递多个参数的打印偶数的方法
/// </summary>
/// <param name="n"></param>
private static void PrintEven2(object n)
{
//判断n是否为ParameterTest 类的对象
if (n is ParameterTest)
{
int beginNum = ((ParameterTest)n).beginNum; //获取对象中的第一个参数
int endNum = ((ParameterTest)n).endNum; //获取对象中的第二个参数
for (int i = beginNum; i <= endNum; i++)
{
if (i % 2 == 0)
{
Console.WriteLine(i);
}
}
}
}
/// <summary>
/// Lock先执行奇数在执行偶数
/// </summary>
public void LockPrintEven()
{
lock (this)
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
}
public void LockPrintOdd()
{
lock (this)
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
}
/// <summary>
/// Monitor
/// </summary>
public void MonitorPrintEven()
{
// Monitor 类的用法虽然比 lock 关键字复杂,但其能添加等待获得锁定的超时值,这样就不会无限期等待获得对象锁。
//Monitor.TryEnter(object, 毫秒数);
Monitor.TryEnter(this, 1); //使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。该方法能在指定的毫秒数内结束线程,这样能避免线程之间的死锁现象。
Monitor.Enter(this);
try
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
finally
{
Monitor.Exit(this);
}
}
public void MonitorPrintOdd()
{
Monitor.Enter(this);
try
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
finally
{
Monitor.Exit(this);
}
}
}
}
/// <summary>
/// 线程传递多个参数的构造方法
/// </summary>
public class ParameterTest
{
public int beginNum;
public int endNum;
public ParameterTest(int a, int b)
{
this.beginNum = a;
this.endNum = b;
}
}