(一)CSharp-多线程编程

news/2025/1/20 7:42:29/

一、进程与线程

1、进程
一个正在运行的程序的实例,是系统进行调度和资源分配的一个独立单位。

进程由两部分能组成:

(1)操作系统用来管理进程的内核对象。内核对象是系统的一种资源,系统对象一旦产生,任何应用程序都可以开启并使用该对象。系统给予内核对象一个计数值作为管理之用。

(2)操作系统用来管理地址的空间。它包含所有可执行模块或 DLL 模块的代码和数据。它还包含动态内存分配的空间,如线程堆栈和堆栈分配空间。

进程分为系统进程和用户进程。程序是静止的,二进程是动态的。

2、线程

一段完成某个特定功能的代码,是程序中的一个执行流。

线程由两个部分组成:

(1)操作系统用来管理线程的内核对象。内核对象也是系统用来存放线程统计信息的地方。
(2)另一个是线程的堆栈。它用于维护线程在执行代码时需要的所有函数的参数的局部变量。

线程是在它的进程地址空间中执行代码的,并且在地址的进程空间中对数据进行操作。

线程分为用户界面线程和工作线程。

1、线程与进程的比较

多进程是指在操作系统中能同时运行多个任务程序。

(1)进程的特点是允许计算机同时运行两个或更多的程序。

(2)在基于线程的多任务处理环境中,线程是最小的处理单位。

(3)多个进程的内部数据和状态都是完全独立的,而多线程共享一块内存空间和一组系统资源,有可能互相影响。

(4)线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程的切换负担要小。

二、C# 中多线程的开发

1、线程操作

System.Threading.Thread

表-Thread 类的常用属性

属性名描述
CurrentThread只读属性,获取当前正在运行的线程
IsAlive判断线程是否处于活动状态
IsBackground获取或设置一个值,该值指示某个线程是否为后台线程
IsThreadPoolThread获取一个值,该值指示线程是否属于托管线程池
Name获取或设置线程的名称
PriorityThreadPriority 枚举类型,代表线程的优先级,如:Normal、AboveNormal、BelowNormal、Highest、Lowest
ThreadStateThreadState 枚举类型,代表当前线程的状态,如:Unstarted、Running、WaitSleepJoin、Stopped、AbortRequested、Susppended、Aborted 等

表-Thread 类的常用方法

方法名描述
GetDomain()返回当前线程所在的应用程序域
GetDomainID()返回当前线程所在的应用程序域的 ID
Start()启动线程的执行
Suspend()挂起线程,或者如果线程已挂起,则不起作用
Resume()继续已挂起的线程
Interrupt()终止处于 Wait 或者 Sleep 或者 Join 线程状态的线程
Join()阻塞调用线程,直到某个线程终止时为止
Sleep()将当前线程阻塞指定的毫秒数
Abort()终止一个线程的运行。如果线程已经终止,则不能通过 Thrread.Start() 来启动线程

2、线程的控制操作

(1)创建线程

static void Main(string[] args){Thread t1 = new Thread(new ThreadStart(Thread1));//创建线程t1.Start();//启动线程Console.ReadKey();}public static void Thread1(){Console.WriteLine("This is a Thread test!");}

(2) 启动线程

t1.Start();

(3)休眠线程

线程的休眠是让当前的线程进入一定时间的休眠状态,时间一到线程将继续执行。

Thread.Sleep(1000);//线程休眠 1000 毫秒
TimeSpan WaitTime = new TimeSpan(0,0,0,0,1000);
Thread.Sleep(WaitTime);//线程休眠按天 小时 分钟 秒 毫秒计

(4)挂起线程

线程的挂起是暂停线程,如果不再启动线程,它将永远保持暂停状态。

if(t1.ThreadState == ThreadState.Running)//判断线程是否正在运行t1.Suspend();

(5)继续线程

已经挂起的线程可以使用 Thread 类的 Resume 方法继续运行。

if(t1.ThreadState == ThreadState.Suspended)//判断线程是否已被挂起t1.Resume();

(6)终止线程

if(t1.IsAlive)//判断线程是否处于活动状态t1.Abort();

3、线程同步

要求一个线程对共享资源访问完全结束后,再让另一个线程访问该资源,必须保证一个共享资源一次只能被一个线程使用。

(1)加锁(Lock)

lock(expression) statement_block

expression: 加锁的对象,必须是引用类型。如果是类的实例,使用 this。如果保护一个静态成员,格式为:lock(typeof(类名)){ }

statement_block: 代表共享资源,在一个时刻内只能被一个线程执行。

(2)监视器(Monitor)

Monitor 类是一个静态类。Monitor 类通过使用 Enter 方法向单个线程授予获取锁定对象的钥匙来控制对对象的访问,该钥匙提供限制访问代码块(通常称为临界区,由 Monitor 类的 Enter 方法标记临界区的开头,Exit 方法标记临界区的结尾)的功能。当一个线程拥有对象的钥匙时,其他任何线程都不能获取该钥匙。

表-Monitor 类的常用方法

方法名描述
Enter()获取锁定对象的钥匙,同时标记临界区的开头。如果此时正有另外一个线程掌管这把钥匙,该方法将进入阻塞状态,直到锁定的对象被打开,如果同一线程正掌管钥匙,再次调用 Enter 方法将不会阻塞
TryEnter()和 Enter 方法类似,不同的是,当对象正被其他线程使用时,该方法不会自动阻塞,而是返回一个 false 值表明失败
Exit()结束对一个对象的监视,即交出锁定对象的钥匙,同时标记受锁定对象保护的临界区的结尾
Pulse()该方法通知位于等待队列中的下一个线程进入就绪队列,一旦调用该方法的线程释放钥匙后,就绪队列的线程就可以获取钥匙
PulseAll()和 Pulse 方法相似,通知等待队列中的所有线程转移到就绪队列中
Wait()释放对象的锁,并阻止当前线程直到它重新获取该锁

(3)互斥体(Mutex)

互斥体是通过只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。

表-Mutex 类的构造函数及方法重载说明

函数原型描述
public Mutex()调用此构造函数相当于带哦用构造函数 public Mutex(false),将互斥体的初始所属权指定为 false,即调用线程不拥有互斥体所有权
public Mutex(bool initiallyOwned)如果 initiallyOwned 为 false,则使用情况同上,如果为 true,则表示调用线程拥有互斥体的初始所有权
public Mutex(bool initiallyOwned, string name)第一个参数使用情况同上。第二个参数表示用字符串 name 作为该互斥体的名称来初始化 Mutex 类的新实例,如果 name 值为空引用,则 Mutex 是未命名的
public Mutex(bool initiallyOwned, string name, out bool createdNew)前两个参数同上。第三个参数是用来在该方法返回时指示调用线程是否被授予了互斥体的初始所有权,如果调用线程被授予了互斥体的初始所有权,则方法返回时 createdNew 为 true,否则为 false
public Mutex(bool initiallyOwned, string name, out bool createdNew, MutexSecurity mutexSecurity)前三个参数同上。第四个参数用于指示该已命名的互斥体的访问控制安全性
public virtual bool WaitOne()用于请求互斥体的所有权
public virtual bool WaitOne(TimeSpan timeout, bool exitContex) 、public virtual bool WaitOne(int milliseconds Timeout, bool exitContex)第一个参数用于指定等待时间,如果超过等待时间线程还没有获取互斥体,WaitOne 方法将返回 false。第二个参数用来指定在开始等待之前,是否先退出调用上下文所在的同步域(如果处于同步上下文中),exitContext 为 true,则等待之前先退出上下文的同步域,否则为 false
public bool ReleasedMutex()用于释放已经拥有的互斥体

三、多线程示例

模拟一家人削苹果和吃苹果的实例。

生产者: 爸爸妈妈作为生产者,不断削苹果往盘子里放。
消费者: 有三个孩子。老大、老二、老三不断从盘子里取苹果吃。
盘子: 盘子数,可放苹果总数,有从盘子里存放和取出苹果的功能。

1)定义盘子(Dish)

使用到 lock (this)、Monitor.Wait(this)、Monitor.PulseAll(this)、Thread.CurrentThread.Abort()

 class Dish{int f = 5;//盘子最多只能放5个苹果EatAppleSmp oEAP;int EnabledNum;//可放苹果总数int n = 0;public Dish(EatAppleSmp oEAP, int EnabledNum){this.oEAP = oEAP;this.EnabledNum = EnabledNum;}//放苹果public void put(string name){lock (this)//苹果已满,线程等待{while (f == 0)//苹果已满,线程等待{try{System.Console.WriteLine(name + "正在等待放入苹果");Monitor.Wait(this);}catch (ThreadInterruptedException) { }}f = f - 1;//削完一个苹果放一次n = n + 1;System.Console.WriteLine(name + "放1个苹果");Monitor.PulseAll(this);if (n > EnabledNum)Thread.CurrentThread.Abort();}}//取苹果public void get(string name){lock (this)//同步控制取苹果{while (f == 5){try{System.Console.WriteLine(name + "等待取苹果");Monitor.Wait(this);}catch (ThreadInterruptedException) { }}f = f + 1;System.Console.WriteLine(name + "取苹果吃...");Monitor.PulseAll(this);}}}

2)定义生产者(Productor)

使用到 Thread.Sleep()

  //生产者class Productor{private Dish dish;private string name;public Productor(string name, Dish dish){this.name = name;this.dish = dish;}public void run(){while (true){dish.put(name);try{Thread.Sleep(600);//削苹果时间}catch (ThreadInterruptedException) { }}}}

3)定义消费者(Consumer)

使用到 Thread.Sleep()

 //消费者class Consumer{private string name;private Dish dish;private int timelong;public Consumer(string name, Dish dish, int timelong){this.name = name;this.dish = dish;this.timelong = timelong;}public void run(){while (true){dish.get(name);try{Thread.Sleep(timelong);//吃苹果时间}catch (ThreadInterruptedException) { }}}}

4) 开启线程,执行削苹果和取苹果的功能

class EatAppleSmp{public EatAppleSmp(){Thread th_mother, th_father, th_young, th_middle, th_old;Dish dish = new Dish(this, 30);//生产者Productor mother = new Productor("妈妈", dish);Productor father = new Productor("爸爸", dish);//消费者Consumer old = new Consumer("老大", dish, 1000);Consumer middle = new Consumer("老二", dish, 1000);Consumer young = new Consumer("老三", dish, 1000);//建立线程th_mother = new Thread(new ThreadStart(mother.run));th_father = new Thread(new ThreadStart(father.run));th_old = new Thread(new ThreadStart(old.run));th_middle = new Thread(new ThreadStart(middle.run));th_young = new Thread(new ThreadStart(young.run));th_mother.Priority = ThreadPriority.Highest;//设置优先级th_father.Priority = ThreadPriority.Normal;th_old.Priority = ThreadPriority.Lowest;th_middle.Priority = ThreadPriority.Normal;th_young.Priority = ThreadPriority.Highest;th_mother.Start();th_father.Start();th_old.Start();th_middle.Start();th_young.Start();}}

5) 在主线程里执行

class Program{static void Main(string[] args){EatAppleSmp mainstart = new EatAppleSmp();Console.ReadKey();}}

输出结果:

妈妈放1个苹果
爸爸放1个苹果
老三取苹果吃...
老二取苹果吃...
老大等待取苹果
妈妈放1个苹果
爸爸放1个苹果
老大取苹果吃...
老二取苹果吃...
老三等待取苹果
妈妈放1个苹果
老三取苹果吃...
爸爸放1个苹果
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老大取苹果吃...
爸爸放1个苹果
妈妈放1个苹果
老二取苹果吃...
老三取苹果吃...
爸爸放1个苹果
妈妈放1个苹果
老大取苹果吃...
爸爸放1个苹果
妈妈放1个苹果
老二取苹果吃...
老三取苹果吃...
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老大取苹果吃...
妈妈放1个苹果
爸爸放1个苹果
老二取苹果吃...
老三取苹果吃...
老大取苹果吃...
老二取苹果吃...
老三取苹果吃...
老大等待取苹果
老二等待取苹果
老三等待取苹果

http://www.ppmy.cn/news/582859.html

相关文章

【三维编辑】Editing Conditional Radiance Fields 编辑条件辐射场

Editing Conditional Radiance Fields(ICCV 2021) 作者单位:Steven Liu, Xiuming Zhang, Zhoutong Zhang, Richard Zhang MIT, Adobe Research, CMU 代码地址:https://github.com/stevliu/editnerf 文章目录 摘要前言一、相关工作…

综合使用各类方法,彻底关闭win10自动更新

目录 一:禁用window update服务 二:在策略中关闭win10自动更新的相关设置 三:任务计划内的Win10更新 四:在注册表中关闭Win10自动更新 结果: 另一种针对注册表的方法: 各个网站文章,作者找了很久…

windows7 使用激活工具激活系统出现的问题汇总

1.激活后卡在logo界面一动不动。 在网上查询可能是因为无法正常读取硬盘导致的。可以将硬盘线拔开,之后进入BIOS界面恢复初始设置,之后再重新插好硬盘线即可正常开机。 2.激活后重新开机打开任何软件都提示缺失user32.dll。 这个可以在cmd中输入sfc /sca…

win7系统一键还原功能怎么进行禁用教学分享

win7系统一键还原功能怎么进行禁用教学分享。有的用户家里有小孩会使用电脑,担心自己的电脑被小孩进行了一键还原,造成数据的丢失,所以想要去进行改功能的禁用。那么如何去进行禁用的设置呢?一起来看看详细的操作方法教学吧。 操作…

Windows xp home edition 安装程序的产品密钥

Windows XP Home Edition 简体中文零售版原版 CD-KEY:BQJG2-2MJT7-H7F6K-XW98B-4HQRQ Windows XP Home Edition 简体中文OEM版 CD-KEY:JQ4T4-8VM63-6WFBK-KTT29-V8966

winrar5.31 专用激活key

RAR registration data 吾爱破解永久授权 Unlimited Company License UID5b2cd25a94422dbad9a7 6412212250d9a73974a519b3adc819906ee860f98a8344d5f8bf8f e7966653fd172bee328c60fce6cb5ffde62890079861be57638717 7131ced835ed65cc743d9777f2ea71a8e32c7e593cf66794343565 b4…

windows7激活文件备份

\Windows\System32\spp\tokens\pkeyconfig\pkeyconfig.xrm-ms \Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareProtectingPlatform\tokens.dat 1、备份以上两个文件,同时保存好激活CD-KEY(注意:appdata是隐藏的…

[win7] window 7 home basic - administrator帐号的激活

一般品牌机预装了win7,可几乎都是家庭版,所以很多功能都是受限制了. 比如win7旗舰版中,激活administrator帐号,只需如下操作即可完成: 控制面板-->管理工具-->计算机管理-->本地用户和组-->用户-->鼠标右键单击administrator选属性--〉将帐户已禁用的钩去掉--〉…