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 线程同步
在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...
随机推荐
- Web Server 在iis下部署php网站在iis下
Web Server 在iis下部署php网站在iis下 一.参考地址: windows8 http://www.cnblogs.com/haocool/archive/2012/10/14/win ...
- 人工智能热门图书(深度学习、TensorFlow)免费送!
欢迎访问网易云社区,了解更多网易技术产品运营经验. 这个双十一,人工智能市场火爆,从智能音箱到智能分拣机器人,人工智能已逐渐渗透到我们的生活的方方面面.网易云社区联合博文视点为大家带来人工智能热门图书 ...
- 【转】PHP微信上传永久图片素材
$TOKEN="XXXX"; $file = "D:\www\weixin\game.jpg"; $data = array( 'media'=> new ...
- 【微框架】之一:从零开始,轻松搞定SpringCloud微服务系列--开山篇(spring boot 小demo)
Spring顶级框架有众多,那么接下的篇幅,我将重点讲解SpringCloud微框架的实现 Spring 顶级项目,包含众多,我们重点学习一下,SpringCloud项目以及SpringBoot项目 ...
- i++操作非原子的验证代码
package incre; public class Incre { public static void main(String[] args) { class Count implements ...
- Python导入命令 import from
一 module通常模块为一个文件,直接使用import来导入就好了.可以作为module的文件类型有".py".".pyo".".pyc" ...
- Qt 学习之路 2(17):文件对话框
Home / Qt 学习之路 2 / Qt 学习之路 2(17):文件对话框 Qt 学习之路 2(17):文件对话框 豆子 2012年9月24日 Qt 学习之路 2 85条评论 在前面的章节中 ...
- react 部分语法补充
jsx语法 todolist.js import React, { Component,Fragment } from 'react'; import './style.css' class Todo ...
- Python文件操作,异常语法
1.文件 2.异常 1.文件的输入输出 #1.打开文件 open 函数open(file,[option])#file 是要打开的文件#option是可选择的参数,常见有 mode 等#2.文件的打 ...
- C语言实践
初学者往往有这样的困惑: 教程也阅读了,知识点也理解了,但是真正编写代码起来无从下手. 连一些基本的小程序都不能完成. 究其原因,就是缺少实践,没有培养起编程思维. 没有处理相关问题的经验. 编程能力 ...