当前位置:
首页 > 编程开发 > Objective-C编程 >
-
C#中的多线程定义
多线程就是使程序并发(同时)执行几个操作。
.NET 框架类库在System.Threading 中加入了多线程的能力。因此要在前面加入引用 using System.Threading
Thread 类:创建并控制线程,设置其优先级并获取其状态。
Thread 类的构造方法,主要有2种:
(1)Thread thread_name=Thread(ThreadStart):ThreadStart 委托,它表示此线程开始执行时要调用的方法。适用于无参数的方法。
(2)Thread thread_name=Thread(ParameterizedThreadStart):ParameterizedThreadStart 委托,它表示此线程开始执行时要调用的方法。适用于有参数传入的方法。
一个普通的无参线程操作
//定义一个线程,参数是一个方法,无返回值,采用的是委托
Thread td = new Thread(xunhuan);
//前台线程,所有的线程都执行完了,应用程序才退出,默认的都是前台线程
//后台线程,所有的前台线程都执行完了,就退出,不管后台的线程
td.IsBackground = true; //设定为后台线程
td.Start();//启动线程
//定义一个线程,参数是一个方法,无返回值,采用的是委托
Thread td = new Thread(xunhuan);
//前台线程,所有的线程都执行完了,应用程序才退出,默认的都是前台线程
//后台线程,所有的前台线程都执行完了,就退出,不管后台的线程
td.IsBackground = true; //设定为后台线程
td.Start();//启动线程
一个普通的有参线程操作
//定义线程,传入的带参数的方法。
Thread ptd = new Thread(showname);
ptd.IsBackground = true;
//重载Start方法,传递个参数
ptd.Start("lilei");
有参的方法定义,参数objec类型
//线程调用,带多个参数
static void shownames(object names)
{
List list = names as List;
foreach (string name in list)
{
MessageBox.Show(name);
}
}
线程状态
任何时候,线程都要处于某种线程状态中。
新线程在Unstarted状态中开始它的生命周期。在调用Thread类的Start方法之前,会一直保持在Unstarted状态,调用方法之后,就会进入Started状态,并立即将程序的控制权返回调用程序(点了线程调用后,可以立即去干别的事)。然后,调用了Start方法的线程(也就是Started线程)和程序中其他的线程并发执行。
线程优先级
每个线程都有个优先级,其范围在ThreadPriority.Lowest和ThreadPriority.Highest之间。默认情况下,每个线程的优先级都是Normal。
Windows操作系统支持时间分片(timeslicing)的概念,它的思路是优先级相同的线程共享一个处理器。
线程的同步和类监视器
通常,多个执行线程要操作共享数据。如果有权访问共享数据的线程只能读取数据,那就不需要阻止多个线程同时访问共享数据。然而,当多个线程共享数据,并且其中一个或多个线程要修改数据时,可能会出现无法预知的结果。如果一个线程正在更新数据,另一个线程也试图更新,那么数据所反映的就第二次更新操作之后的结果。
所以可通过一次只允许一个线程访问用于操作共享数据的代码来解决。其他想要操作数据的线程应该等待。具有排他访问权的线程完成对数据的操作后,等待操作线程的数据可以继续执行。这称为互斥或线程同步。
C#提供了两中解决技术:
(1)Monitor类:主要方法(方法传入的参数为objec对象,一般为当前调用的线程):
Monitor.Enter():获取排他锁。
Monitor.Wait():释放对象上的锁并阻止当前线程,直到重新获取该锁。
Monitor.Pulse():通知等待队列中的线程对象状态的改变。
Monitor.Exit():释放排他锁。
(2)lock关键字:
在对象前加个lock
代码示例
Monitor的用法
public class mt
{
private int age;
//buff判断内容是否已被更新或提取,0为未更新,1为已更新
private int buff = 0;
int Age
{
get
{
Monitor.Enter(this);//获取此对象的排他锁
if (buff == 0)//若内容为空或未更新就使此线程等待
{
MessageBox.Show("内容为空或未更新");
Monitor.Wait(this);//释放锁并等待
}
buff--;
MessageBox.Show("读取内容");
Monitor.Pulse(this); //通知等待队列的线程,此对象状态要更改
Monitor.Exit(this);//释放排他锁
return age;
}
set
{
Monitor.Enter(this);
if (buff == 1)
{
MessageBox.Show("内容还没被读取");
Monitor.Wait(this);
}
buff++;
MessageBox.Show("写入内容"+value);
age = value;
Monitor.Pulse(this);
Monitor.Exit(this);
}
}
}
lock的用法
int Age2
{
get
{
lock(this) //开始阶段,自获取了排他锁
{
if (buff == 0)//若内容为空或未更新就使此线程等待
{
MessageBox.Show("内容为空或未更新");
Monitor.Wait(this);//释放锁并等待
}
buff--;
MessageBox.Show("读取内容");
Monitor.Pulse(this); //通知等待队列的线程,此对象状态要更改
return age;
}//结束阶段,释放了排他锁
}
set
{
lock (this)
{
if (buff == 1)
{
MessageBox.Show("内容还没被读取");
Monitor.Wait(this);
}
buff++;
MessageBox.Show("写入内容" + value);
age = value;
Monitor.Pulse(this);
}
}
}
Monitor注意的地方:用Monitor类的Enter方法和Exit方法来管理对象的锁时,要想释放锁,必须显式调用Exit方法。调用Exit方法之前如果某个方法中引发了一个异常,并且这个异常没有被捕捉到,方法就会终止,而且不会调用Exit方法。因此锁没有被释放。为了避免这种错误,可以将可能引发异常的代码放入一个try模块,并将对Exit方法的调用放在相应的finally块上以确保释放锁。
使用一个Lock块来管理同步对象上的锁,可以避免忘记调用Monitor类的Exit方法来释放锁。Lock处于某种原因而终止时,C#会隐式调用Monitor类的exit方法。如此一来,即使在代码中出现异常,也可以将锁释放。
.NET 框架类库在System.Threading 中加入了多线程的能力。因此要在前面加入引用 using System.Threading
Thread 类:创建并控制线程,设置其优先级并获取其状态。
Thread 类的构造方法,主要有2种:
(1)Thread thread_name=Thread(ThreadStart):ThreadStart 委托,它表示此线程开始执行时要调用的方法。适用于无参数的方法。
(2)Thread thread_name=Thread(ParameterizedThreadStart):ParameterizedThreadStart 委托,它表示此线程开始执行时要调用的方法。适用于有参数传入的方法。
一个普通的无参线程操作
//定义一个线程,参数是一个方法,无返回值,采用的是委托
Thread td = new Thread(xunhuan);
//前台线程,所有的线程都执行完了,应用程序才退出,默认的都是前台线程
//后台线程,所有的前台线程都执行完了,就退出,不管后台的线程
td.IsBackground = true; //设定为后台线程
td.Start();//启动线程
//定义一个线程,参数是一个方法,无返回值,采用的是委托
Thread td = new Thread(xunhuan);
//前台线程,所有的线程都执行完了,应用程序才退出,默认的都是前台线程
//后台线程,所有的前台线程都执行完了,就退出,不管后台的线程
td.IsBackground = true; //设定为后台线程
td.Start();//启动线程
一个普通的有参线程操作
//定义线程,传入的带参数的方法。
Thread ptd = new Thread(showname);
ptd.IsBackground = true;
//重载Start方法,传递个参数
ptd.Start("lilei");
有参的方法定义,参数objec类型
//线程调用,带多个参数
static void shownames(object names)
{
List list = names as List;
foreach (string name in list)
{
MessageBox.Show(name);
}
}
线程状态
任何时候,线程都要处于某种线程状态中。
新线程在Unstarted状态中开始它的生命周期。在调用Thread类的Start方法之前,会一直保持在Unstarted状态,调用方法之后,就会进入Started状态,并立即将程序的控制权返回调用程序(点了线程调用后,可以立即去干别的事)。然后,调用了Start方法的线程(也就是Started线程)和程序中其他的线程并发执行。
线程优先级
每个线程都有个优先级,其范围在ThreadPriority.Lowest和ThreadPriority.Highest之间。默认情况下,每个线程的优先级都是Normal。
Windows操作系统支持时间分片(timeslicing)的概念,它的思路是优先级相同的线程共享一个处理器。
通常,多个执行线程要操作共享数据。如果有权访问共享数据的线程只能读取数据,那就不需要阻止多个线程同时访问共享数据。然而,当多个线程共享数据,并且其中一个或多个线程要修改数据时,可能会出现无法预知的结果。如果一个线程正在更新数据,另一个线程也试图更新,那么数据所反映的就第二次更新操作之后的结果。
所以可通过一次只允许一个线程访问用于操作共享数据的代码来解决。其他想要操作数据的线程应该等待。具有排他访问权的线程完成对数据的操作后,等待操作线程的数据可以继续执行。这称为互斥或线程同步。
C#提供了两中解决技术:
(1)Monitor类:主要方法(方法传入的参数为objec对象,一般为当前调用的线程):
Monitor.Enter():获取排他锁。
Monitor.Wait():释放对象上的锁并阻止当前线程,直到重新获取该锁。
Monitor.Pulse():通知等待队列中的线程对象状态的改变。
Monitor.Exit():释放排他锁。
(2)lock关键字:
在对象前加个lock
代码示例
Monitor的用法
public class mt
{
private int age;
//buff判断内容是否已被更新或提取,0为未更新,1为已更新
private int buff = 0;
int Age
{
get
{
Monitor.Enter(this);//获取此对象的排他锁
if (buff == 0)//若内容为空或未更新就使此线程等待
{
MessageBox.Show("内容为空或未更新");
Monitor.Wait(this);//释放锁并等待
}
buff--;
MessageBox.Show("读取内容");
Monitor.Pulse(this); //通知等待队列的线程,此对象状态要更改
Monitor.Exit(this);//释放排他锁
return age;
}
set
{
Monitor.Enter(this);
if (buff == 1)
{
MessageBox.Show("内容还没被读取");
Monitor.Wait(this);
}
buff++;
MessageBox.Show("写入内容"+value);
age = value;
Monitor.Pulse(this);
Monitor.Exit(this);
}
}
}
lock的用法
int Age2
{
get
{
lock(this) //开始阶段,自获取了排他锁
{
if (buff == 0)//若内容为空或未更新就使此线程等待
{
MessageBox.Show("内容为空或未更新");
Monitor.Wait(this);//释放锁并等待
}
buff--;
MessageBox.Show("读取内容");
Monitor.Pulse(this); //通知等待队列的线程,此对象状态要更改
return age;
}//结束阶段,释放了排他锁
}
set
{
lock (this)
{
if (buff == 1)
{
MessageBox.Show("内容还没被读取");
Monitor.Wait(this);
}
buff++;
MessageBox.Show("写入内容" + value);
age = value;
Monitor.Pulse(this);
}
}
}
Monitor注意的地方:用Monitor类的Enter方法和Exit方法来管理对象的锁时,要想释放锁,必须显式调用Exit方法。调用Exit方法之前如果某个方法中引发了一个异常,并且这个异常没有被捕捉到,方法就会终止,而且不会调用Exit方法。因此锁没有被释放。为了避免这种错误,可以将可能引发异常的代码放入一个try模块,并将对Exit方法的调用放在相应的finally块上以确保释放锁。
使用一个Lock块来管理同步对象上的锁,可以避免忘记调用Monitor类的Exit方法来释放锁。Lock处于某种原因而终止时,C#会隐式调用Monitor类的exit方法。如此一来,即使在代码中出现异常,也可以将锁释放。
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
JavaScript判断两个数组相等的四类方法
js如何操作video标签
React实战--利用甘特图和看板,强化Paas平
【记录】正则替换的偏方
前端下载 Blob 类型整理
抽象语法树AST必知必会
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程