C# 多线程
发布日期:2021-05-10 05:29:47 浏览次数:21 分类:精选文章

本文共 6358 字,大约阅读时间需要 21 分钟。

目录

1. 线程概述

1.1 线程的概念

  • 线程是进程中的执行流程,一个进程可以有多个线程,每个线程可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。

1.2 多线程的优缺点

  • 优点:
    • 通过网络与Wed服务器的数据库进行通信;
    • 执行占用大量时间的操作;
    • 区分具有不同优先级的任务;
    • 使用户界面可以在将时间分配给后台任务时仍能快速作出反应。
  • 缺点:
    • 系统将为进程和线程所需的上下文信息使用内存。创建进程和线程的数量会受到可用内存的限制;
    • 跟踪大量的线程将占用大量的处理器时间。如果线程过多,则其中大多数线程都不会产生明显的进度。如果大多数线程处于一个进程中,则其他进程中的线程的调度频率就会低很多。
    • 使用多个线程控制代码执行变得复杂;
    • 销毁线程需要了解可能发生的问题并进行处理。

2. 线程的实现

2.1 Thread类创建线程

在这里插入图片描述

//移动的按钮using System.Threading;namespace ExThread1{       public partial class Form1 : Form    {           public Form1()        {               InitializeComponent();            CheckForIllegalCrossThreadCalls = false;//让线程可以调用窗体控件        }        int x = 12;        void Roll()        {               while(x<=260)            {                   button1.Location = new Point(x, 12);                Thread.Sleep(500);  //线程休眠                x += 4;                if(x>=260)                {                       x = 12;                }            }        }        private void Form1_Load(object sender, EventArgs e)        {               Thread th = new Thread(new ThreadStart(Roll));//创建线程对象            th.Start();  //启动线程        }    }}

2.2 线程的生命周期

在这里插入图片描述

3. 线程操作

3.1 线程的休眠

Thread.Sleep(500);//休眠500msThread.Sleep(-1);//无限期阻塞Thread.Sleep(Timeout.Infinite);//无限期阻塞

3.2 线程的加入

  • 假如当前程序为多线程程序且存在一个线程A,现在需要插入线程B,并要求线程B执行完毕后,再继续执行线程A,此时可以用Thread类中的join方法实现。

3.3 线程的终止

  • 线程的Abort方法用于永久地停止托管线程。调用Abort方法时,公共语言运行库在目标线程中引发ThreadAbortException异常,目标线程可以捕捉此异常。一旦线程被终止,它将无法重新启动。

3.4 线程的优先级

  • 线程是根据优先级调度执行的;
  • 具有最高优先级的线程总是最先执行;
  • 只要具有较高优先级的线程可以运行,较低优先级的线程就不会执行;
  • 如果多个具有相同优先级的线程可用,程序将遍历处于该优先级的线程,并为每个线程提供一个固定的时间片来执行;
  • 如果具有较高优先级的线程可以运行时,较低优先级的线程就会被抢先,并允许较高优先级的线程再次执行。
//优先级从低到高thread1.Priority = ThreadPriority.Lowest;       //0thread1.Priority = ThreadPriority.BelowNormal;  //1thread1.Priority = ThreadPriority.Normal;       //2thread1.Priority = ThreadPriority.AboveNormal;  //3thread1.Priority = ThreadPriority.Highest;      //4

3.5 示例代码

在这里插入图片描述

using System.Threading;//线程的加入  控制进度条的滚动namespace ScrollBarThread{       public partial class Form1 : Form    {           public Form1()        {               InitializeComponent();            CheckForIllegalCrossThreadCalls = false;        }        Thread thread1;        Thread thread2;        void Func1()        {               try            {                   int count = 0;                while (true)                {                       progressBar1.PerformStep();                    count += progressBar1.Step;                    Thread.Sleep(500);                    if (count == 20)                    {                           thread2.Join();                    }                }            }            catch(ThreadAbortException)            {                   MessageBox.Show("线程1被终止");            }        }        void Func2()        {               int count = 0;            while (true)            {                   progressBar2.PerformStep();                count += progressBar2.Step;                Thread.Sleep(500);                if (count == 100)                {                       break;                }            }        }        private void Form1_Load(object sender, EventArgs e)        {               thread1 = new Thread(Func1);            thread1.Start();            thread2 = new Thread(Func2);            thread2.Start();        }        private void button1_Click(object sender, EventArgs e)        {               if(thread1.IsAlive)            {                   thread1.Abort();            }                   }        private void button2_Click(object sender, EventArgs e)        {               if(thread2.IsAlive)            {                   thread2.Abort();            }                    }    }}

4. 线程同步

4.1 线程同步机制

  • 为了解决多线程资源共享的问题,需要给共享资源上一道锁;
  • 线程同步是指并发线程高效、有序地访问共享资源所采用的技术。
  • 同步是指某一时刻只有一个线程可以访问资源,只有当资源所有者自动放弃了代码或资源的所有权时,其他线程才可以使用这些资源。

4.2 实现线程同步的3种方法

4.2.1 lock

  • lock关键字可以确保代码块完成运行,而不会被其他线程中断,它是通过在代码块运行期间为给定对象获取互斥锁来实现的。

4.2.2 Monitor

  • Monitor类提供了同步对象的访问机制,它通过向当个线程授予对象锁来控制对象的访问,对象锁提供限制访问代码块(通常称为临界区)的能力。
  • 当一个线程拥有对象锁时,其他任何线程都不能获取该锁。

Monitor类的主要功能

  • 根据需要与某个对象关联;
  • 它是未绑定的,也就是说可以直接从任何上下文调用它;
  • 不能创建Monitor类的实例。

Monitor常用方法

  • Enter:在指定对象上获取排他锁。
  • Exit:释放指定对象上的排他锁。
  • Pulse:通知等待队列中的线程锁定对象状态的更改。
  • PulseAll:通知所有的等待线程对象状态的修改。
  • TryEnter:试图获取指定对象的排他锁。
  • Wait:释放对象上的锁并阻塞当前线程,直到它重新获取该锁。

4.2.3 Mutex

  • Mutex类是同步基元,它只向一个线程授予对共享资源的独占访问权。
  • 如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
  • Mutex与Monitor类似,它防止多个线程在某一实践同时执行某个代码块,然而与监视器不同的是,Mutex类可以用来跨进程的线程同步。

Mutex类的常用方法:

  • Close:在派生类中被重写时,释放由当前WaitHaldle持有的所有资源。
  • Release:释放Mutex一次。
  • WaitAll:等待指定数组中的所有元素都收到信号。
  • WaitAny:等待指定数组中的任一元素收到信号。
  • WaitOne:当在派生类中重写时,阻塞当前线程,直到当前的WaitHandle收到信号。

4.3 示例代码

说明

  • 尽管Mutex类可以用于进程内的线程同步,但是使用Monitor更为可取,因为Monitor监视器是专门为.NET Framework而设计的,因而它可以更好地利用资源。相比之下,Mutex类是Win32构造的包装。尽管Mutex类比监视器更为强大,但是相对于Monitor类,它所需的互操作转换更消耗计算资源。
using System.Threading;namespace ThreadLock{       class Program    {           int num = 10;//票数        void Ticket()        {               while(true)            {                   //1. lock(this)        //锁定代码块                //2. Monitor.Enter(this);//锁定代码块                //3. Mutex mutex = new Mutex();//创建对象  没有起作用,不知道为什么                //   mutex.WaitOne();                //阻塞当前线程                {                       if(num>0)                    {                           Thread.Sleep(100);                        Console.WriteLine(Thread.CurrentThread.Name + "------票数" + num--);                    }                }                //2. Monitor.Exit(this);//解锁代码块                //3. mutex.ReleaseMutex();   //释放Mutex对象            }        }        static void Main(string[] args)        {               Program p = new Program();            Thread t1 = new Thread(p.Ticket);            Thread t2 = new Thread(p.Ticket);            Thread t3 = new Thread(p.Ticket);            Thread t4 = new Thread(p.Ticket);            t1.Name = "线程1";            t2.Name = "线程2";            t3.Name = "线程3";            t4.Name = "线程4";            t1.Start();            t2.Start();            t3.Start();            t4.Start();            Console.ReadKey();        }    }}

5. 过时的方法和线程池

5.1 过时的方法

  • 由于Suspend方法和Resume方法很容易造成死锁,目前函数已经废弃不用。

5.2 线程池

  • 每创建一个线程,在带来便利的同时,也会带来某些不确定的负面因素,比如管理成本、未知Bug等,如果程序中需要创建大量短生命周期的线程,则应该使用线程池。
  • 在C#中提供了创建线程池的ThreadPool类,该类提供了一些静态方法,用于发送工作项、处理异步I/O、代表其他线程等待以及处理计时器等。
  • 例如,GetMaxThreads方法可以检索同时处于活动状态的线程池请求的数目;GetMinThreads方法可以检索线程池在新请求预测中维护的空闲线程数等。

6. 相关代码下载地址:

链接:https://pan.baidu.com/s/1iaNrRat3Eo8R-7BEwj1MRw

提取码:fzvj

上一篇:Halcon 圆形标定板标定基本流程-标定助手操作
下一篇:C# .NET与数据结构

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月06日 20时11分40秒