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

         */
    }

}

posted @ 2021-12-15 17:53  highlightyys  阅读(33)  评论(0编辑  收藏  举报