C# 多线程之线程同步
多线程间应尽量避免同步问题,最好不要线程间共享数据。如果必须要共享数据,就需要使用同步技术,确保一次只有一个线程访问和改变共享状态。
一::lock语句
lock语句事设置锁定和接触锁定的一种简单方法。其语法非常简单:
lock (obj)
{
// 需要发生同步的代码区
}
将共享数据的操作代码,放在上述的“{...}”区域内。锁定的对象(obj)必须是引用类型,如果锁定一个值类型,实际是锁定了它的一个副本,并没有实现锁定功能。
一般地,被锁定对象需要被创建为 私有 只读 引用类型:
private readonly object obj = new object();
二::Interlocked类
Interlocked类用于使变量的简单语句原子化。它提供了以线程安全的方式递增、递减、交换和读取值的方法。
private int stateFlag = ; public int IncrementState
{
//get
//{
// lock (this)
// {
// stateFlag++;
// return stateFlag;
// }
//} get
{
return Interlocked.Increment(ref stateFlag); // using System.Threading; //Interlocked.Decrement(ref V0);
//Interlocked.Exchange(ref V1, ref V2);
//Interlocked.Read(ref V0);
}
}
三::Monitor类
与lock相似,C#的lock语句被编译器解析为使用Monitor类。锁定开始相当于 Monitor.Enter(obj) 方法,该方法会一直等待,直到线程被对象锁定。解除锁定后线程进入同步阶段,使用 Monitor.Exit(obj)方法解除锁定,编译器将它与try块的finally结合。方法一中的代码,相当于:
Monitor.Enter(obj);
try
{
// 需要发生同步的代码区
}
finally
{
Monitor.Exit(obj);
}
与lock语句相比,Monitor类的优点在于:可以添加一个等待北锁定的超时值。这样就不会无限期等待被锁定,而可以使用 TryEnter() 方法,给一个超时参数。
bool lockTaken = false;
Monitor.TryEnter(obj, , ref lockTaken);
if (lockTaken)
{
try
{
// acquired the lock
// synchronized region for obj
}
finally
{
Monitor.Exit(obj);
}
}
else
{
// didn't get the lock,do something else
}
如果obj被锁定,TryEnter() 方法就会把 bool 型引用参数 lockTaken 设置为 true,并同步地访问由 obj 锁定的状态。如果另一线程 锁定 obj 的时间超过 500 毫秒,Try Enter() 方法就把变量 lockTaken 设为 false ,线程不再等待,而是用于执行其它操作。也许在之后,该线程会尝试再次被锁定。
四::SpinLock结构
它是一个结构体(struct),用法极类似于Monitor类。获得锁用 Enter()或TryEnter() 方法,释放锁用 Exit() 方法。它还提供了属性 IsHeld 和 IsHeldByCurrentThred ,指定当前是否被锁定。
SpinLock mSpinLock = new SpinLock(); // 最好只是用一个 SpinLock public void fun1()
{
// ..... bool lockTaken = false;
mSpinLock.Enter(ref lockTaken);
try
{
// synchronized region
}
finally
{
mSpinLock.Exit();
} // ...
}
public void fun2()
{
// ..... bool lockTaken = false;
mSpinLock.TryEnter(, ref lockTaken);
if (lockTaken)
{
try
{
// synchronized region
}
finally
{
mSpinLock.Exit();
}
}
else
{
// didn't get the lock,do something else
} // ...
}
SpinLock结构体是 .Net 4 新增。它适用于:有大量的锁,且锁定时间都非常短。程序需要避免使用多个 SpinLock 结构,也不要调用任何可能阻塞的内容。
五::WaitHandle 基类
WaitHandle是一个抽象基类,用于等待一个信号的设置。可以等待不同的信号,因为WaitHandle是一个基类,可以从中派生一些类。
public delegate int TakesAWhileDelegate(int data, int ms); // 声明委托
public void Main()
{
TakesAWhileDelegate vTAwdl = TakesAWhile;
IAsyncResult vAr = vTAwdl.BeginInvoke(, , null, null);
while(true)
{
Console.Write(".");
if (vAr.AsyncWaitHandle.WaitOne(, false)) // 等待 vAr.AsyncWaitHandle 收到信号(超时300毫秒)
{
Console.WriteLine("Can get the result now.");
break;
}
}
int result = vTAwdl.EndInvoke(vAr);
Console.WriteLine("Result:{0}", result);
Console.Read();
} int TakesAWhile(int data, int ms)
{
Console.WriteLine("TakesAWhile started");
Thread.Sleep(ms);
Console.WriteLine("TakesAWhile completed");
return ++data;
}
以上实例代码,使用”异步委托", BeginInvoke() 方法返回一个实现了 IAsycResult接口的对象。使用 IAsycResult 接口,可以用AsycResult属性访问 WaitHandle 基类。在调用WaitOne()方法时,线程等待一个与等待句柄相关的信号。
使用 WaitHandle 类可以等待一个信号出现(WaitOne()方法)、等待必须发出信号的多个对象(WaitAll()方法)、或者等待多个对象中的一个(WaitAny()方法)。后两者事WaitHandle类的静态方法,接收一个WaitHandle参数数组。
六::Mutex类
Mutex(mutual exclusion,互斥)是 .NET Framework中提供跨多个进程同步访问的一个类。所以,它常被用于“程序单一启动控制”。
/// <summary>
/// 单一进程 检查,如果已经运行一个进程,返回false,表示检查不通过。否则返回true。
/// </summary>
/// <returns></returns>
private bool RunOnceCheck()
{
bool vExist;
Mutex nMutex = new Mutex(false, "SingletonWinAppMutex", out vExist);
if (!vExist)
{
// 表示已经启动一个了,应退出当前启动
return false;
}
return true;
}
它非常类似于Monitor类,因为他们都只有一个线程能拥有锁定。只有一个线程能获得互斥锁定,访问受互斥保护的同步代码区域。Mutex派生自基类WaitHandle,因此可以利用WaitOne()方法获得互斥锁定,在该过程中成为该互斥的拥有者。调用 ReleaseMutex()方法,释放互斥。
bool createdNew;
Mutex mutex = new Mutex(false, "ProCSharpMutex", out createdNew); if (mutex.WaitOne())
{
try
{
// synchronized region
}
finally
{
mutex.ReleaseMutex();
}
}
else
{
// some problem happened while waiting
}
七::Semaphore类
Semaphore非常类似于互斥,其区别在于Semaphore可以同时由多个线程使用。它是一种计数互斥锁定,可以定义允许同时访问受其锁定保护的资源的线程个数。它适用于:有许多可用资源,且只允许一定数量的线程访问该资源。
八::Events类
它是一种可以在系统范围内同步资源的方法。
九::Barrier类
它非常适用于其中工作有很多个任务分支且以后又需要合并工作的情况。
十::ReaderWriterLockSlim类
为了使锁定机制允许锁定多个读取器(而不是一个写入器)访问某个资源,可以使用此类。它提供了一个锁定功能,如果没有写入器锁定资源,就允许多个读取器访问资源,但只能有一个写入器锁定该资源。
C# 多线程之线程同步的更多相关文章
- C#多线程之线程同步篇3
在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...
- C#多线程之线程同步篇2
在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...
- C#多线程之线程同步篇1
在多线程(线程同步)中,我们将学习多线程中操作共享资源的技术,学习到的知识点如下所示: 执行基本的原子操作 使用Mutex构造 使用SemaphoreSlim构造 使用AutoResetEvent构造 ...
- 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock
[源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...
- 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent
[源码下载] 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEve ...
- IOS 多线程,线程同步的三种方式
本文主要是讲述 IOS 多线程,线程同步的三种方式,更多IOS技术知识,请登陆疯狂软件教育官网. 一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IO ...
- 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)
Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...
- Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...
- MFC——9.多线程与线程同步
Lesson9:多线程与线程同步 程序.进程和线程是操作系统的重点,在计算机编程中.多线程技术是提高程序性能的重要手段. 本文主要解说操作系统中程序.进程和线程之间的关系,并通过相互排斥对象和事件对象 ...
- Java多线程 3 线程同步
在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...
随机推荐
- javascript dom与字符串相互转换
js dom与字符串相互转换 一.字符串转换dom: function stringToDom(str){ var obj=document.createElement("div" ...
- SoftKeyboard在AndroidStudio下的配置和运行
前文翻译的<Android下创建一个输入法>一文中提到了来自Google的输入法例程SoftKeyboard,备忘下该程序的配置和运行. 首先将SoftKeyboard导入AndroidS ...
- STL学习笔记--临时对象的产生与运用
所谓的临时对象,就是一种无名对象(unnamed objects).它的出现如果不在程序员的预期之下,往往造成效率上的负担.但有时刻意制造一些临时对象,却又是使程序干净清爽的技巧.刻意制造临时对象的方 ...
- Java-BubbleSort
前言 我们都知道BubbleSort这种排序算法不管从大到小排序,还是从小到大排序,都是相邻的两个进行比较,然后不符合条件时交换顺序.下面来看看引用类型是怎么进行BubbleSort的. 内容 需求: ...
- loj #6235. 区间素数个数 min_12.5筛
\(\color{#0066ff}{ 题目描述 }\) 求 \(1\sim n\) 之间素数个数. \(\color{#0066ff}{输入格式}\) 一行一个数 n . \(\color{#0066 ...
- CF431B Shower Line
Many students live in a dormitory. A dormitory is a whole new world of funny amusements and possibil ...
- FMDB----SQL----数据库
#pragma mark -- 数库 - (void)createDatabase{ //路径 NSString *path = [NSString stringWithFormat:@"% ...
- windows mysql导入sql文件
当需要的sql文件很大时(>200M)怎么办?答:修改my.ini文件,max_allowed_packet的值可以设置为1024M 进入mysql.exe目录下,执行如下命令: mysql - ...
- php小试牛刀
[构造函数] function __construct() [析构函数] 当某个对象的所有引用被删除,或者对象被显式的销毁时会执行析构函数 function __destruct() [静态方法] p ...
- 【记录一下】从0到1 我的python开发之路
请设计实现一个商城系统,商城主要提供两个功能:商品管理.会员管理. 商品管理: - 查看商品列表 - 根据关键字搜索指定商品 - 录入商品 会员管理:[无需开发,如选择则提示此功能不可用,正在开发中, ...