C#进程与线程
来源:C#进程与线程
using System;
using System.Diagnostics;
using System.Threading;
namespace Demo_20201213
{
class Program
{
static void Main(string[] args)
{
//Console.WriteLine("Hello World!");
// DemoProcess();
//DemoThread();
//DemoPriority();
//DemoLock();
//DemoMonitor();
DemoMutex();
Console.ReadKey();
}
//进程
public static void DemoProcess()
{
Process[] processes = Process.GetProcesses();//查看所有进程
string filename = processes[0].ProcessName;
Process p = new Process();
p.StartInfo.FileName = "mspaint"; //设置进程名称
p.Start(); //启动进程
Console.WriteLine(p.MachineName.ToString());
Console.WriteLine(p.Id.ToString());
Console.WriteLine(p.StartTime);
Console.WriteLine(p.Threads);
//根据进程名称获取进程
Process[] processes1 = Process.GetProcessesByName("mspaint");
if (processes1.Length > 0)
{
try
{
foreach (Process p2 in processes1)
{
if (!p2.HasExited)
{
p2.Kill();//关闭进程
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
//线程
public static void DemoThread()
{
//线程(Thread)是包含在进程中的,它位于 System.Threading 命名空间中
//使用线程时首先需要创建线程,在使用 Thread 类的构造方法创建其实例时,需要用到 ThreadStart 委托或者 ParameterizedThreadStart 委托创建 Thread 类的实例
//ThreadStart 委托只能用于无返回值、无参数的方法,ParameterizedThreadStart 委托则可以用于带参数的方法。
//创建线程并启动
ThreadStart ts1 = new ThreadStart(PrintEven); //使用 Threadstart 委托为 PrintEven 方法创建了线程
Thread t1 = new Thread(ts1);
ThreadStart ts2 = new ThreadStart(PrintOdd);
Thread t2 = new Thread(ts2);
t1.Start();
t2.Start();
//不是按照线程的调用顺序先打印出所有的偶数再打印奇数
//在使用 ParameterizedThreadStart 委托调用带参数的方法时,方法中的参数只能是 object 类型并且只能含有一个参数
ParameterizedThreadStart pts1 = new ParameterizedThreadStart(PrintEven2);
Thread t3 = new Thread(pts1);
t3.Start(15);
ParameterizedThreadStart pts2 = new ParameterizedThreadStart(PrintEven3);
Thread t4 = new Thread(pts2);
//通过为 ParameterTest 类中的字段赋值,并将其通过线程的 Start 方法传递给委托引用的方法 PrintEven,即可实现在委托引用的方法中传递多个参数的操作
ParameterTest pt = new ParameterTest(1, 10);
t4.Start(pt);
}
//线程 - 优先级
public static void DemoPriority()
{
//在 C# 中线程的优先级使用线程的 Priority 属性设置即可,默认的优先级是 Normal
//优先级的值通过 ThreadPriority 枚举类型来设置,从低到高分别为Lowest、BelowNormal、Normal、AboveNormal、Highest。
//通过优先级是不能控制线程中的先后执行顺序的,只能是优先级高的线程优先执行的次数多而已。
ThreadStart ts1 = new ThreadStart(PrintEven);
Thread t1 = new Thread(ts1);
t1.Priority = ThreadPriority.Lowest;
ThreadStart ts2 = new ThreadStart(PrintOdd);
Thread t2 = new Thread(ts2);
t2.Priority = ThreadPriority.Highest; //设置优先级
t1.Start();
//让线程休眠 1 秒
Thread.Sleep(1000);
t2.Start();
//线程状态控制的方法包括暂停线程 (Sleep)、中断线程 (Interrupt)、挂起线程 (Suspend)、唤醒线程 (Resume)、终止线程 (Abort)。
//Thread.CurrentThread.Abort(); 用于方法内,终止线程,已弃用
//由于挂起线程(Suspend) 和唤醒线程(Resume) 的操作很容易造成线程的死锁状态,已经被弃用了,而是使用标识字段来设置线程挂起和唤醒的状态。
//所谓线程死锁就是多个线程之间处于相互等待的状态。
//线程分为前台线程和后台线程,前台线程不用等主程序结束,后台线程则需要应用程序运行结束后才能结束。
//在应用程序运行结束后,后台线程即使没有运行完也会结束,前台线程必须等待自身线程运行结束后才会结束。
//使用 Thread 对象的 IsBackground 属性来判断线程是否为后台线程。
ThreadStart ts = new ThreadStart(GiveRedEnvelop);
Thread t = new Thread(ts);
t.Start();
if (t.IsBackground == false)
{
Console.WriteLine("该线程不是后台线程!");
t.IsBackground = true;
}
else
{
Console.WriteLine("该线程是后台线程!");
}
}
//实现线程同步可以使用 lock 关键字和 Monitor 类、Mutex 类来解决
public static void DemoLock()
{
//虽然 Sleep 方法能控制线程的暂停时间,从而改变多个线程之间的先后顺序,但每次调用线程的结果是随机的
//线程同步的方法是将线程资源共享,允许控制每次执行一个线程,并交替执行每个线程。
//在 C# 语言中实现线程同步可以使用 lock 关键字和 Monitor 类、Mutex 类来解决。
//通过 lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程。
Program program = new Program();
ThreadStart ts1 = new ThreadStart(program.PrintEven4);
Thread t1 = new Thread(ts1);
t1.Name = "打印偶数的线程";
t1.Start();
ThreadStart ts2 = new ThreadStart(program.PrintOdd4);
Thread t2 = new Thread(ts2);
t2.Name = "打印奇数的线程";
t2.Start();
}
public static void DemoMonitor()
{
//Program p = new Program();
//ThreadStart ts1 = new ThreadStart(p.PrintEven5);
//Thread t1 = new Thread(ts1);
//t1.Name = "print even num";
//t1.Start();
//ThreadStart ts2 = new ThreadStart(p.PrintOdd5);
//Thread t2 = new Thread(ts2);
//t2.Name = "print odd num";
//t2.Start();
//Monitor 类的用法虽然比 lock 关键字复杂,但其能添加等待获得锁定的超时值,这样就不会无限期等待获得对象锁。
//使用 TryEnter() 方法可以给它传送一个超时值,决定等待获得对象锁的最长时间。
//Monitor.TryEnter(object, 毫秒数 );
//该方法能在指定的毫秒数内结束线程,这样能避免线程之间的死锁现象。
//此外,还能使用 Monitor 类中的 Wait() 方法让线程等待一定的时间,使用 Pulse() 方法通知处于等待状态的线程。
//1.Monitor.Wait方法
//当线程调用 Wait 时,它释放对象的锁并进入对象的等待队列,对象的就绪队列中的下一个线程(如果有)获取锁并拥有对对象的独占使用。Wait()就是交出锁的使用权,使线程处于阻塞状态,直到再次获得锁的使用权。
//2.Monitor.Pulse方法
//当前线程调用此方法以便向队列中的下一个线程发出锁的信号。接收到脉冲后,等待线程就被移动到就绪队列中。在调用 Pulse 的线程释放锁后,就绪队列中的下一个线程(不一定是接收到脉冲的线程)将获得该锁。pulse()并不会使当前线程释放锁。
//共用同一lock对象两线程不能只调用Wait(),Wait这个方法反而放弃了锁的使用权,同时阻塞当前线程,线程就直接休眠(进入WaitSleepJoin状态),同时在主线程中Join这个work线程时,也就一直不能返回了。线程将一直阻塞。
//Assembly code
//| -拥有锁的线程 lockObj->| -就绪队列(ready queue) | -等待队列(wait queue)
//当一个线程尝试着lock一个同步对象的时候,该线程就在就绪队列中排队。一旦没人拥有该同步对象,就绪队列中的线程就可以占有该同步对象。这也是我们平时最经常用的lock方法。
//为了其他的同步目的,占有同步对象的线程也可以暂时放弃同步对象,并把自己流放到等待队列中去。这就是Monitor.Wait。由于该线程放弃了同步对象,其他在就绪队列的排队者就可以进而拥有同步对象。
//比起就绪队列来说,在等待队列中排队的线程更像是二等公民:他们不能自动得到同步对象,甚至不能自动升舱到就绪队列。而Monitor.Pulse的作用就是开一次门,使得一个正在等待队列中的线程升舱到就绪队列;相应的Monitor.PulseAll则打开门放所有等待队列中的线程到就绪队列。
LockMe l = new LockMe(); //尽管这两个线程都有自己的LockMe对象(WaitPulse1, WaitPulse2),但是它们都引用同一个对象。
WaitPalsel e1 = new WaitPalsel(l);
WaitPulse2 e2 = new WaitPulse2(l);
Thread t1 = new Thread(new ThreadStart(e1.CriticalSection));
t1.Start();
Thread t2 = new Thread(new ThreadStart(e2.CriticalSection));
t2.Start();
}
public static void DemoMutex()
{
//Mutex 类也是用于线程同步操作的类,例如,当多个线程同时访问一个资源时保证一次只能有一个线程访问资源。
ParameterizedThreadStart ts = new ParameterizedThreadStart(PakingSpace);
Thread t1 = new Thread(ts);
t1.Start("冀A12345");
Thread t2 = new Thread(ts);
t2.Start("京A00000");
}
//打印偶数
public static void PrintEven()
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
}
//打印奇数
public static void PrintOdd()
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(i);
}
}
public static void PrintEven2(object n)
{
for (int i = 0; i <= (int)n; i = i + 2)
{
Console.WriteLine(i);
}
}
public static void PrintEven3(object n)
{
int start = ((ParameterTest)n).beginNum;
int end = ((ParameterTest)n).endNum;
for (int i = start; i <= (int)end; i = i + 2)
{
Console.WriteLine(i);
}
}
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 void PrintEven4()
{
lock (this)
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
}
private void PrintOdd4()
{
//通过 lock 关键字能保证加锁的线程只有在执行完成后才能执行其他线程。
lock (this)
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
}
private void PrintEven5()
{
Monitor.Enter(this);
try
{
for (int i = 0; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
finally
{
Monitor.Exit(this);
}
}
private void PrintOdd5()
{
Monitor.Enter(this);
try
{
for (int i = 1; i <= 10; i = i + 2)
{
Console.WriteLine(Thread.CurrentThread.Name + "--" + i);
}
}
finally
{
Monitor.Exit(this);
}
}
private static Mutex mutex = new Mutex();
public static void PakingSpace(object num)
{
if (mutex.WaitOne()) //WaitOne() 方法用于等待资源被释放, ReleaseMutex() 方法用于释放资源。WaitOne() 方法在等待 ReleaseMutex() 方法执行后才会结束。
{
try
{
Console.WriteLine("车牌号{0}的车驶入!", num);
Thread.Sleep(1000);
}
finally
{
Console.WriteLine("车牌号{0}的车离开!", num);
mutex.ReleaseMutex();
}
}
}
}
/*
车牌号冀A12345的车驶入!
车牌号冀A12345的车离开!
车牌号京A00000的车驶入!
车牌号京A00000的车离开!
*/
public class ParameterTest
{
public int beginNum;
public int endNum;
public ParameterTest(int a, int b)
{
this.beginNum = a;
this.endNum = b;
}
}
public class LockMe
{
}
class WaitPalsel
{
private int result = 0;
private LockMe lM;
public WaitPalsel(LockMe l)
{
this.lM = l;
}
public void CriticalSection()
{
Monitor.Enter(this.lM);
Console.WriteLine("WaitPulse1: Entered Thread " + Thread.CurrentThread.GetHashCode());
for (int i = 1; i <= 5; i++)
{
Monitor.Wait(this.lM); //当线程执行Monitor.Wait()方法时,它会暂时释放LockMe对象上的锁,这样其他线程就可以访问LockMe对象;访问这个对象的线程就会一直等待直到被唤醒
Console.WriteLine("WaitPulse1: Result =" + result++ + "ThreadID"
+ Thread.CurrentThread.GetHashCode());
Monitor.Pulse(this.lM); //用来通知等待的线程醒来的
}
Console.WriteLine("WaitPulse1: Exiting Thread " + Thread.CurrentThread.GetHashCode());
Monitor.Exit(this.lM);
}
}
class WaitPulse2
{
private int result = 0;
private LockMe lM;
public WaitPulse2()
{ }
public WaitPulse2(LockMe l)
{
this.lM = l;
}
public void CriticalSection()
{
Monitor.Enter(this.lM);
Console.WriteLine("WaitPulse2: Entered Thread " + Thread.CurrentThread.GetHashCode());
for (int i = 1; i < 5; i++)
{
Monitor.Pulse(this.lM);
Console.WriteLine("WaitPulse2: Result =" + result++ + "ThreadID"
+ Thread.CurrentThread.GetHashCode());
Monitor.Wait(this.lM);
Console.WriteLine("WaitPulse2: WokeUp");
}
Console.WriteLine("WaitPulse2 Exiing Thread " + Thread.CurrentThread.GetHashCode());
Monitor.Exit(this.lM);
}
/*
WaitPulse1: Entered Thread 7
WaitPulse2: Entered Thread 8
WaitPulse2: Result =0ThreadID8
WaitPulse1: Result =0ThreadID7
WaitPulse2: WokeUp
WaitPulse2: Result =1ThreadID8
WaitPulse1: Result =1ThreadID7
WaitPulse2: WokeUp
WaitPulse2: Result =2ThreadID8
WaitPulse1: Result =2ThreadID7
WaitPulse2: WokeUp
WaitPulse2: Result =3ThreadID8
WaitPulse1: Result =3ThreadID7
WaitPulse2: WokeUp
WaitPulse2 Exiing Thread 8
*/
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律