C#并发编程-4 同步
如果程序用到了并发技术,那就要特别留意这种情况:一段代码需要修改数据,同时其他代码需要访问同一个数据。
这种情况就需要考虑同步地访问数据。
如果下面三个条件都满足,就必须用同步来保护共享的数据。
多段代码正在并发运行;
这几段代码在访问(读或写)同一个数据;
至少有一段代码在修改(写)数据。
一 阻塞锁
如果有多个线程需要安全地读写共享数据,这种情况可以考虑使用lock语句。
一个线程进入锁后,在锁被释放之前其他线程是无法进入的:
class MyClass
{
private readonly object _mutex = new object();
private int _value;
public void Increment()
{
lock (_mutex)
{
_value = _value + 1;
}
}
}
.NET 框 架 中 还 有 很 多 其 他 类 型 的 锁, 如 Monitor、SpinLock、ReaderWriterLockSlim。
关于lock的使用,有四条重要的准则:
限制锁的作用范围:
要尽量限制锁的作用范围。应该把 lock 语句使用的对象设为私有成员,并且永远不要暴露给非本类的方法。
每个类型通常最多只有一个锁。如果一个类型有多个锁,可考虑通过重构把它分拆成多个独立的类型。
lock可以锁定任何引用类型,但是建议为 lock 语句定义一个专用的成员,就像上例中那样。
文档中明确锁保护的内容;
锁范围内的代码尽量少:在锁定时执行的代码要尽可能得少。要特别小心阻塞调用。在锁定时不要做任何阻塞操作。
在控制锁的时候绝不运行随意的代码:
在锁定时绝不要调用随意的代码。随意的代码包括引发事件、调用虚拟方法、调用委托。
如果一定要运行随意的代码,就在释放锁之后运行。
二 异步锁
如果多个代码块需要安全地读写共享数据,并且这些代码块可能使用 await 语句,可以考虑使用SemaphoreSlim。
class MyClass1
{
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private int _value; public async Task DelayAndIncrementAsync()
{
await _mutex.WaitAsync();
try
{
var oldValue = _value;
await Task.Delay(TimeSpan.FromSeconds(oldValue));
_value = oldValue + 1;
}
finally
{
_mutex.Release();
}
}
}
三 阻塞信号
如果需要从一个线程发送信号给另一个线程,可以考虑使用ManualResetEventSlim。
一个ManualResetEventSlim的对象处于这两种状态其中之一:标记的(signaled)或未标记的(unsignaled)。
每个线程都可以把事件设置为signaled 状态,也可以把它重置为 unsignaled 状态。线程也可等待事件变为 signaled 状态。
下面的两个方法被两个独立的线程调用,一个线程等待另一个线程的信号:
class MyClass2
{
private readonly ManualResetEventSlim _mres = new ManualResetEventSlim();
private int _value;
public int WaitForInitialization()
{
_mres.Wait();
return _value;
}
public void InitializeFromAnotherThread()
{
_value = 13;
_mres.Set();
}
}
在 .NET 框架中,还有一些线程同步信号类型。ManualResetEvent、AutoResetEvent、CountdownEvent。
四 异步信号
需要在代码的各个部分间发送通知,并且要求接收方必须进行异步等待。
如果该通知只需要发送一次,那可用 TaskCompletionSource<T> 异步发送。
发送代码调用TrySetResult,接收代码等待它的 Task 属性:
class MyClass3
{
private readonly TaskCompletionSource<object> _tcs = new TaskCompletionSource<object>();
private int _value1;
private int _value2;
public async Task<int> WaitForInitializationAsync()
{
await _tcs.Task;
return _value1 + _value2;
}
public void Initialize()
{
_value1 = 13;
_value2 = 17;
_tcs.TrySetResult(null);
}
}
以上。
C#并发编程-4 同步的更多相关文章
- Java并发编程:同步容器
Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...
- 【转】Java并发编程:同步容器
为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch).今天我们就来讨论下同步容器. ...
- 8、Java并发编程:同步容器
Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...
- Python并发编程-线程同步(线程安全)
Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...
- Java并发编程之同步
1.synchronized 关键字 synchronized 锁什么?锁对象. 可能锁对象包括: this, 临界资源对象,Class 类对象. 1.1 同步方法 synchronized T me ...
- Python并发编程之同步\异步and阻塞\非阻塞
一.什么是进程 进程: 正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 进程和程序的区别: 程序仅仅只是一堆代码而已,而进程指的是程序的运行过程. 需要强调的是:同一个程序执行两次,那也 ...
- Java并发编程:同步锁、读写锁
之前我们说过线程安全问题可以用锁机制来解决,即线程必要要先获得锁,之后才能进行其他操作.其实在 Java 的 API 中有这样一些锁类可以提供给我们使用,与其他对象作为锁相比,它们具有更强大的功能. ...
- Java并发编程之同步/并发集合
同步集合 Java中同步集合如下: Vector:基于数组的线程安全集合,扩容默认增加1倍(ArrayList50%) Stack:继承于Vector,基于动态数组实现的一个线程安全的栈 Hashta ...
- Java并发编程基础——同步
一.synchronized 关键字 1)synchronized 锁什么?锁对象.可能锁对象包括: this, 临界资源对象,Class 类对象.如同下面例子所示: package cn.test. ...
随机推荐
- 使用Three.js实现炫酷的赛博朋克风格3D数字地球大屏 🌐
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 近期工作有涉及到数字大屏的需求,于是利用业余时间,结合 Three.js ...
- 在Linux虚拟机中添加多个固定ip地址
1.右键点击设置2.点击添加,再点击网络适配器,最后点击完成.3.选择完成后的网络适配器,选择仅主机模式.4.用roott身份登录,用nmtui进行设置 systemctl start Network ...
- 带你徒手完成基于MindSpore的CycleGAN实现
摘要:CycleGAN图像翻译模型,由两个生成网络和两个判别网络组成,通过非成对的图片将某一类图片转换成另外一类图片,可用于风格迁移 本文分享自华为云社区<基于MindSpore的CycleGA ...
- 如何开发一款基于 vite+vue3 的在线表格系统(下)
在上篇内容中我们为大家分享了详细介绍Vue3和Vite的相关内容.在本篇中我们将从项目实战出发带大家了解Vite+Vue3 的在线表格系统的构建. 使用Vite初始化Vue3项目 在这里需要注意:根据 ...
- Spring 02: Spring接管下的三层项目架构
业务背景 需求:使用三层架构开发,将用户信息导入到数据库中 目标:初步熟悉三层架构开发 核心操作:开发两套项目,对比Spring接管下的三层项目构建和传统三层项目构建的区别 注意:本例中的数据访问层, ...
- synchronized原理剖析
synchronized原理剖析 并发编程存在什么问题? 1️⃣ 可见性 可见性:是指当一个线程对共享变量进行了修改,那么另外的线程可以立即看到修改后的最新值. 案例演示:一个线程A根据 boolea ...
- windows绕过杀软添加账户密码
windows绕过杀软添加账户密码 起因:system权限下存在杀软无法添加账户信息 绕过方法 1.C#脚本 运行后会在目标机器上创建一个用户为 wh4am1 密码为 qqai@love 的 Admi ...
- 三 单例模式【Singleton Pattern】 来自CBF4LIFE 的设计模式
这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,单例就是单一.独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还有什么不能山寨的呢?我们举个比较难复制的 ...
- ViewBinding 与 Kotlin 委托双剑合璧
请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭 ...
- java 类名后加变量名是什么意思?
回答这个问题我们需要先了解两个事情: A是一个类,我们如果对他进行实例化,需要这样写: A a = new A(); 详细解释一下这个语句,首先等号左边做的事情:在JVM栈内存(stack)中定义了一 ...