C#基础知识及题目练习 Day14 进程和线程

 

一、进程和线程理论知识

进程:正在被操作系统运行的程序,一个进程中包含多个线程。

线程:CPU执行的基本逻辑单元

    

1、进程类

进程类:Process  操作进程 用于启动、停止、监控和管理进程
GetProcesses():获取所有正在运行的进程
StartInfo:进程的启动信息(启动哪个进程)

2、线程

(1)Thread 类

Thread 类是用于控制线程的基础类,它存在于 System.Threading 命名空间。通过 Thread 可以控制当前应用程序域中线程的创建、挂起、停止、销毁

属性

说明

Name

获取或设置线程的名称

ThreadState

获取当前线程的运行状态

CurrentThread

获取当前正在运行的线程

Priority

获取或设置线程调度的优先级别

方法

说明

Start

启动执行线程

Suspend

挂起线程,如果线程已挂起,则方法无效

Resume

恢复被挂起的线程

Join

阻塞线程,直到线程终止或任务执行完毕

Abort

终止线程运行

 

(2)单线程:

带来的问题:点击按钮,循环打印1-10000,界面会陷入假死状态

每运行一个程序,就会分配一个主线程工作

解决方案:创建一个子线程去执行这个方法

所有的前台线程都关闭,程序才会关闭;前台线程一旦关闭,后台线程自动关闭,所以上述应改成后台线程

th.IsBackground=true;

eg1:单线程应用程序 ,委托打印1-10

       static void Main(string[] args)
        {
            //创建不带参数方法的委托对象
            ThreadStart ts = new ThreadStart(OutPut);
            Thread thread = new Thread(ts);
            thread.Start();
            
            Console.ReadKey(true);//按任意键退出
        }
        static void OutPut()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
            }
        }

例:将i值显示到TextBox中,会报异常:从不是创建它的线程上访问它

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //ThreadStart te = new ThreadStart(Test);
            Thread th = new Thread(Test);
            th.Start(); //启动线程
        }
        public void Test()
        {
            string str = "";
            for (int i = 0; i <= 1000000; i++)
            {
                str += i.ToString();
            }
            textBox1.Text = str;
        }
    }

.net中不允许跨线程调用

解决方案:Control.CheckForIllegalCrossThreadCalls = false;

 

问题又来了,中途点击关闭按钮的时候,程序会抛异常,因为主线程已经关闭,子线程调用不到主线程上的控件,解决方案:

 

(3)多线程:

可以让程序同时做多个事儿  线程创建步骤。

eg2:多线程应用程序

       static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "主线程";
            //创建第1个子线程
            ThreadStart ts = new ThreadStart(Output);
            Thread thread1 = new Thread(ts);
            thread1.Name = "子线程1";
            thread1.Start();

            //创建第二个子线程
            Thread thread2 = new Thread(ts);
            thread2.Name = "子线程2";
            thread2.Start();

            //主线程调用Output方法
            Program.Output();
     }

输出结果顺序混乱

原因在于CPU在执行任务时是分时执行的;并且与双核(多核)CPU有关

            thread1.Name = "子线程1";
            //启动子线程
            ();

            //创建第二个子thread1.Start();
            thread1.Join线程
            Thread thread2 = new Thread(ts);
            thread2.Name = "子线程2";
            thread2.Start();
            thread2.Join();

            //主线程调用Output方法
            Program.Output();

Thread1.Jion():Thread1执行,其他线程等待

线程按顺序执行

 

3、使用同步技术解决多线程资源共享

(1)线程的挂起、恢复

thread1.Suspend();//挂起线程

thread1.Resume(); //恢复线程

微软已标记过时,但还可以用!!!!

            Thread.CurrentThread.Name = "主线程";
            //创建第1个子线程
            ThreadStart ts = new ThreadStart(Output);
            Thread thread1 = new Thread(ts);
            thread1.Name = "子线程1";
            //启动子线程
            thread1.Start();

            if (thread1.ThreadState == ThreadState.Running)
            {
                thread1.Suspend();//挂起线程
            }

            Program.Output();

            if (thread1.ThreadState == ThreadState.Suspended)
            {
                thread1.Resume(); //恢复线程
            }
            Console.ReadLine();
        }

        public static void Output()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("线程:{0}, i的值为:{1}", Thread.CurrentThread.Name, i);
            }
        }
    }

 

(2)线程的睡眠与终止:

Thread.Sleep(3000);//使主线程睡眠3秒

        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "主线程";
            //创建第1个子线程
            ThreadStart ts = new ThreadStart(Output);
            Thread thread1 = new Thread(ts);
            thread1.Name = "子线程1";
            thread1.Start();

            Thread.Sleep(3000);//使主线程睡眠3秒

            //主线程调用Output方法
            Program.Output();
            Console.ReadKey(true);
        }
        public static void Output()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("线程:{0}, i的值为:{1}", Thread.CurrentThread.Name, i);
            }
        }

Thread.CurrentThread.Abort();//终止

        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "主线程";
            //创建第1个子线程
            ThreadStart ts = new ThreadStart(Output);
            Thread thread1 = new Thread(ts);
            thread1.Name = "子线程1";
            //启动子线程
            thread1.Start();
           
            thread1.Join();
            Console.ReadKey(true);
        }

        public static void Output()
        {
            try
            {
                for (int i = 0; i < 10000; i++)
                {
                    if (i > 5)
                        Thread.CurrentThread.Abort();

                    Console.WriteLine("线程:{0}, i的值为:{1}", Thread.CurrentThread.Name, i);
                }
            }
            catch (ThreadAbortException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

(3)线程的调度

Thread.CurrentThread .Priority = ThreadPriority.Highest;//优先级最高

成员

说明

Highest

优先级最高

AboveNormal

优先级次之

Normal

优先级在AboveNormal之下,线程的默认优先级

BelowNormal

优先级在Normal之下

Lowest

优先级最低

总结:

当线程需要启动时  th.Start(); //启动线程
当线程需要挂起时  th.Suspend();//挂起线程
当线程需要继续开始时  th.Resume();//继续线程
当线程需要停止时(下班了)  th.Abort();//中止线程

 

4.线程池ThreadPool类的使用

需要调用ThreadPool类中的QueueUserWorkItem 方法:

ThreadPool.QueueUserWorkItem(WaitCallback  waitcallback)

WaitCallback:代表线程要执行的方法,是个委托类型

 

注意:

  • 不能给线程池中的线程设置优先级或线程名称
  • 线程池中的线程适合用于时间较短的任务

 

eg:“费波那契”

编写一个计算前100个“费波那契”数字输出的双线程应用程序,程序中这两个线程都可以完成“费波那契”数字的计算和显示。将这两个线程赋予不同的执行等待时间,同时应能够控制线程的启动、挂起、唤醒和终止。

“费波那契”数字排列格式为:后一个数字是前两个数字之和,例如112358132134…

FebroSeries类:

class FebroSeries
    {
        public long firstValue; //上前一个数字
        public long secondValue;//前一个数字
        private long currentValue;//当前数字值

        public FebroSeries()
        {
            firstValue = 1;
            secondValue = 1;
            currentValue = 0;
        }
        /// <summary>
        /// 计算新数值
        /// </summary>
        /// <returns></returns>
        public long GetResult()
        {
            currentValue = firstValue + secondValue;
            firstValue = secondValue;
            secondValue = currentValue;
            return currentValue;
        }
    }

FebroForm:

public partial class FebroForm : Form
    {
        //声明线程
        Thread fastThread = null;
        Thread slowThread = null;

        public FebroForm()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            //创建快线程,该线程执行FastFebro方法
            fastThread = new Thread(new ThreadStart(FastFebro));
            //创建慢线程,该线程执行SlowFebro方法
            slowThread = new Thread(new ThreadStart(SlowFebro));
            //启动线程
            fastThread.Start();
            slowThread.Start();
            //控制按钮可用状态
            btnStart.Enabled = false; //开始按钮不可用
            btnContinue.Enabled = false;//继续按钮不可用
            btnPause.Enabled = true;//暂停按钮可用
            btnStop.Enabled = true;//停止按钮可用
        }
        private void FastFebro()
        {
            FebroSeries febro = new FebroSeries();
            lstFebro1.Items.Add(febro.firstValue);
            lstFebro1.Items.Add(febro.secondValue);

            for (int i = 0; i < 200; i++)
            {
                //向lstFebro1中添加新的"费波那契"数字
                lstFebro1.Items.Add(febro.GetResult());
                Thread.Sleep(1000);
            }
        }

        private void SlowFebro()
        {
            FebroSeries febro = new FebroSeries();
            lstFebro2.Items.Add(febro.firstValue);
            lstFebro2.Items.Add(febro.secondValue);

            for (int i = 0; i < 200; i++)
            {
                //向lstFebro1中添加新的"费波那契"数字
                lstFebro2.Items.Add(febro.GetResult());
                Thread.Sleep(3000);
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if ((fastThread.ThreadState == ThreadState.Running || fastThread.ThreadState == ThreadState.WaitSleepJoin) && (slowThread.ThreadState == ThreadState.Running || slowThread.ThreadState == ThreadState.WaitSleepJoin))
            {
                //线程挂起
                fastThread.Suspend();
                slowThread.Suspend();

                btnContinue.Enabled = true;//继续按钮可用
                btnPause.Enabled = false;//暂停按钮可用
                btnStart.Enabled = false;//开始按钮可用
                btnStop.Enabled = false;//停止按钮可用
            }
        }

        private void btnContinue_Click(object sender, EventArgs e)
        {
            if (fastThread.ThreadState == ThreadState.Suspended ||
                fastThread.ThreadState == ThreadState.SuspendRequested ||
                slowThread.ThreadState == ThreadState.Suspended ||
                slowThread.ThreadState == ThreadState.SuspendRequested)
            {
                try
                {
                    //唤醒线程
                    fastThread.Resume();
                    slowThread.Resume();

                    btnContinue.Enabled = false;//继续按钮不可用
                    btnPause.Enabled = true;//暂停按钮可用
                    btnStop.Enabled = true;//停止按钮可用
                    btnStart.Enabled = false;//开始按钮可用

                }
                catch (ThreadStateException msg)
                {
                    MessageBox.Show(msg.ToString(), "Exception");
                }
            }
        }

        private void btnEnd_Click(object sender, EventArgs e)
        {
            //线程终止
            fastThread.Abort();
            slowThread.Abort();

            btnStart.Enabled = true;
            btnContinue.Enabled = false;
            btnPause.Enabled = false;
            btnStop.Enabled = false;
        }

        private void FebroForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (fastThread == null && slowThread == null)
            {
                Application.Exit();
            }
            else
            {
                fastThread.Abort();
                slowThread.Abort();
            }
        }
    }

例:播放音乐

例:摇奖机

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值