- 浏览: 510854 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
michao:
大哥,还有aperture.exe吗? 发我一份,找不到呀,m ...
使用aperture框架让AS3与C++通信,执行本地代码 -
Aaron-Joe-William:
文件被删除了。下不了。
SQLite 数据库加密的一种解决方案 -
hanmiao:
樓主的文章不就是來自IBM Developers里的http: ...
mina 入门 -
howesen:
断包与粘包问题,需要处理下就好了
mina接收数据不全(2) -
sniciq:
git clone --recursive git://git ...
ESB学习笔记(Spring Integration实战)
我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在后台处理一大堆数据,但还要使用户界面处于可操作状态;或者你的程序需要访问一些外部资源如数据库或网络文件等。这些情况你都可以创建一个子线程去处理,然而,多线程不可避免地会带来一个问题,就是线程同步的问题。如果这个问题处理不好,我们就会得到一些非预期的结果。 在网上也看过一些关于线程同步的文章,其实线程同步有好几种方法,下面我就简单的做一下归纳。 一、volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的。它只能在变量一级做同步,volatile的含义就是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我。(【转自www.bitsCN.com 】)因此,当多线程同时访问该变量时,都将直接操作主存,从本质上做到了变量共享。 能够被标识为volatile的必须是以下几种类型:(摘自MSDN) 如: 但volatile并不能实现真正的同步,因为它的操作级别只停留在变量级别,而不是原子级别。如果是在单处理器系统中,是没有任何问题的,变量在主存中没有机会被其他人修改,因为只有一个处理器,这就叫作processor Self-Consistency。但在多处理器系统中,可能就会有问题。 每个处理器都有自己的data cach,而且被更新的数据也不一定会立即写回到主存。所以可能会造成不同步,但这种情况很难发生,因为cach的读写速度相当快,flush的频率也相当高,只有在压力测试的时候才有可能发生,而且几率非常非常小。 二、lock关键字 lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的。它可以保证当一个线程在关键代码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。用法: 所以,使用lock应该注意以下几点: 1、如果一个类的实例是public的,最好不要lock(this)。因为使用你的类的人也许不知道你用了lock,如果他new了一个实例,并且对这个实例上锁,就很容易造成死锁。 2、如果MyType是public的,不要lock(typeof(MyType)) 3、永远也不要lock一个字符串 三、System.Threading.Interlocked 对于整数数据类型的简单操作,可以用 Interlocked 类的成员来实现线程同步,存在于System.Threading命名空间。Interlocked类有以下方法:Increment , Decrement , Exchange 和CompareExchange 。使用Increment 和Decrement可以保证对一个整数的加减为一个原子操作。Exchange 方法自动交换指定变量的值。CompareExchange 方法组合了两个操作:比较两个值以及根据比较的结果将第三个值存储在其中一个变量中。比较和交换操作也是按原子操作执行的。如: Output: 四、Monitor Monitor类提供了与lock类似的功能,不过与lock不同的是,它能更好的控制同步块,当调用了Monitor的Enter(Object o)方法时,会获取o的独占权,直到调用Exit(Object o)方法时,才会释放对o的独占权,可以多次调用Enter(Object o)方法,只需要调用同样次数的Exit(Object o)方法即可,Monitor类同时提供了TryEnter(Object o,[int])的一个重载方法,该方法尝试获取o对象的独占权,当获取独占权失败时,将返回false。 但使用 lock 通常比直接使用 Monitor 更可取,一方面是因为 lock 更简洁,另一方面是因为 lock 确保了即使受保护的代码引发异常,也可以释放基础监视器。这是通过 finally 中调用Exit来实现的。事实上,lock 就是用 Monitor 类来实现的。下面两段代码是等效的: 关于用法,请参考下面的代码: 当线程1获取了m_monitorObject对象独占权时,线程2尝试调用TryEnter(m_monitorObject),此时会由于无法获取独占权而返回false,输出信息如下: 另外,Monitor还提供了三个静态方法Monitor.Pulse(Object o),Monitor.PulseAll(Object o)和Monitor.Wait(Object o ) ,用来实现一种唤醒机制的同步。关于这三个方法的用法,可以参考MSDN,这里就不详述了。 五、Mutex 在使用上,Mutex与上述的Monitor比较接近,不过Mutex不具备Wait,Pulse,PulseAll的功能,因此,我们不能使用Mutex实现类似的唤醒的功能。不过Mutex有一个比较大的特点,Mutex是跨进程的,因此我们可以在同一台机器甚至远程的机器上的多个进程上使用同一个互斥体。尽管Mutex也可以实现进程内的线程同步,而且功能也更强大,但这种情况下,还是推荐使用Monitor,因为Mutex类是win32封装的,所以它所需要的互操作转换更耗资源。 六、ReaderWriterLock 在考虑资源访问的时候,惯性上我们会对资源实施lock机制,但是在某些情况下,我们仅仅需要读取资源的数据,而不是修改资源的数据,在这种情况下获取资源的独占权无疑会影响运行效率,因此.Net提供了一种机制,使用ReaderWriterLock进行资源访问时,如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待,参考以下代码: 在程序中,我们启动两个线程获取m_int的读取访问权,使用一个线程获取m_int的写入独占权,执行代码后,输出如下:
可以看到,当WriterThread获取到写入独占权后,任何其它读取的线程都必须等待,直到WriterThread释放掉写入独占权后,才能获取到数据的访问权,应该注意的是,上述打印信息很明显显示出,可以多个线程同时获取数据的读取权,这从ReadThread1和ReadThread2的信息交互输出可以看出。 七、SynchronizationAttribute 当我们确定某个类的实例在同一时刻只能被一个线程访问时,我们可以直接将类标识成Synchronization的,这样,CLR会自动对这个类实施同步机制,实际上,这里面涉及到同步域的概念,当类按如下设计时,我们可以确保类的实例无法被多个线程同时访问 八、MethodImplAttribute 如果临界区是跨越整个方法的,也就是说,整个方法内部的代码都需要上锁的话,使用MethodImplAttribute属性会更简单一些。这样就不用在方法内部加锁了,只需要在方法上面加上 [MethodImpl(MethodImplOptions.Synchronized)] 就可以了,MehthodImpl和MethodImplOptions都在命名空间System.Runtime.CompilerServices 里面。但要注意这个属性会使整个方法加锁,直到方法返回,才释放锁。因此,使用上不太灵活。如果要提前释放锁,则应该使用Monitor或lock。我们来看一个例子:
public class A
{
private volatile int _i;
public int I
{
get { return _i; }
set { _i = value; }
}
}
public void Function()
{
object lockThis = new object ();
lock (lockThis)
{
// Access thread-sensitive resources.
}
}
int i = 0 ;
System.Threading.Interlocked.Increment( ref i);
Console.WriteLine(i);
System.Threading.Interlocked.Decrement( ref i);
Console.WriteLine(i);
System.Threading.Interlocked.Exchange( ref i, 100 );
Console.WriteLine(i);
System.Threading.Interlocked.CompareExchange( ref i, 10 , 100 );
lock (x)
{
DoSomething();
}
等效于
object obj = ( object )x;
System.Threading.Monitor.Enter(obj);
try
{
DoSomething();
}
finally
{
System.Threading.Monitor.Exit(obj);
}
private static object m_monitorObject = new object ();
[STAThread]
static void Main( string [] args)
{
Thread thread = new Thread( new ThreadStart(Do));
thread.Name = " Thread1 " ;
Thread thread2 = new Thread( new ThreadStart(Do));
thread2.Name = " Thread2 " ;
thread.Start();
thread2.Start();
thread.Join();
thread2.Join();
Console.Read();
}
static void Do()
{
if ( ! Monitor.TryEnter(m_monitorObject))
{
Console.WriteLine( " Can't visit Object " + Thread.CurrentThread.Name);
return ;
}
try
{
Monitor.Enter(m_monitorObject);
Console.WriteLine( " Enter Monitor " + Thread.CurrentThread.Name);
Thread.Sleep( 5000 );
}
finally
{
Monitor.Exit(m_monitorObject);
}
}
private static ReaderWriterLock m_readerWriterLock = new ReaderWriterLock();
private static int m_int = 0;
[STAThread]
static void Main(string[] args)
{
Thread readThread = new Thread(new ThreadStart(Read));
readThread.Name = "ReadThread1";
Thread readThread2 = new Thread(new ThreadStart(Read));
readThread2.Name = "ReadThread2";
Thread writeThread = new Thread(new ThreadStart(Writer));
writeThread.Name = "WriterThread";
readThread.Start();
readThread2.Start();
writeThread.Start();
readThread.Join();
readThread2.Join();
writeThread.Join();
Console.ReadLine();
}
private static void Read()
{
while (true)
{
Console.WriteLine("ThreadName " + Thread.CurrentThread.Name + " AcquireReaderLock");
m_readerWriterLock.AcquireReaderLock(10000);
Console.WriteLine(String.Format("ThreadName : {0} m_int : {1}", Thread.CurrentThread.Name, m_int));
m_readerWriterLock.ReleaseReaderLock();
}
}
private static void Writer()
{
while (true)
{
Console.WriteLine("ThreadName " + Thread.CurrentThread.Name + " AcquireWriterLock");
m_readerWriterLock.AcquireWriterLock(1000);
Interlocked.Increment(ref m_int);
Thread.Sleep(5000);
m_readerWriterLock.ReleaseWriterLock();
Console.WriteLine("ThreadName " + Thread.CurrentThread.Name + " ReleaseWriterLock");
}
}
1). 在类的声明中,添加System.Runtime.Remoting.Contexts.SynchronizationAttribute属性。
2). 继承至System.ContextBoundObject
需要注意的是,要实现上述机制,类必须继承至System.ContextBoundObject,换句话说,类必须是上下文绑定的。
一个示范类代码如下:
[System.Runtime.Remoting.Contexts.Synchronization]
public class SynchronizedClass : System.ContextBoundObject
{
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void DoSomeWorkSync()
{
Console.WriteLine( " DoSomeWorkSync() -- Lock held by Thread " +
Thread.CurrentThread.GetHashCode());
Thread.Sleep( 1000 );
Console.WriteLine( " DoSomeWorkSync() -- Lock released by Thread " +
Thread.CurrentThread.GetHashCode());
}
public void DoSomeWorkNoSync()
{
Console.WriteLine( " DoSomeWorkNoSync() -- Entered Thread is " +
Thread.CurrentThread.GetHashCode());
Thread.Sleep( 1000 );
Console.WriteLine( " DoSomeWorkNoSync() -- Leaving Thread is " +
Thread.CurrentThread.GetHashCode());
}
[STAThread]
static void Main( string font-fa
发表评论
-
RichTextBox 添加控件,被禁用如何处理 button
2010-11-01 18:45 1294WPF中RichTextBox的确非 ... -
关于WPF ListView数据绑定 入门 及分类,排序
2010-09-03 18:14 9404不多说,先直接上代码 ... -
关于WPF 数据绑定简单介绍及入门
2010-09-02 20:07 5386今天搞了一下午的数据绑定,由于以前用FLEX的数据绑定很 ... -
何为插件化系统,插件化系统有何优势
2010-08-10 14:28 2394当一个软件项目开 ... -
回调函数原理
2010-08-10 12:04 2244回调函数原理 声明CALLBACK 调用(call ... -
C#制作屏幕保护的方法 函数
2010-08-10 10:16 1491本文介绍使用C#制作屏 ... -
初探C# 异常处理
2010-08-03 10:39 1330一、基础 在C# 里,异 ... -
C#中使用try catch对系统性能的影响和处理机制的学习总结!
2010-08-03 10:31 2851问题1:当一段代码被try ... -
C# WebClient上传下载时进度条显示,找了好久才找到的哦!
2010-07-23 11:05 77252、代码: using System; using Sys ... -
WinFrom通过WebClient上传下载文件(带进度条)
2010-07-23 10:48 4301(2009-09-27 12:18:09) 转 ... -
关于图片保存问题
2010-07-15 20:01 1000如果你在用PngBitmapEncoder之类的 Save图片 ... -
Windows 7 任务栏开发 之 进度条(Progress Bar)
2010-07-12 14:33 2000上一篇 我们完成了“覆盖图标”(Overlay ... -
WPF 新弹出窗口抢焦点问题
2010-06-21 16:34 4126新弹出窗口抢了正在使用的窗口焦点,这个问题烦了好久,今天终于有 ... -
C# 第三方控件
2010-06-08 10:29 3075DevExpress,NetAdvantage 这两套算是最全 ... -
浅析C#中三层架构的实现
2010-06-02 16:14 1634本文讨论如何在C#中实现三层架构,使用MS Acces ... -
数据绑定
2010-05-31 18:42 873http://liutiemeng.blog.51cto.co ... -
C# 修改警告心得
2010-05-22 17:08 14281.(CA1031)如果有try catch最好不要捕获Exc ... -
C# log4net
2010-05-17 13:40 2223说明:本程序演示如何利用log4net记录程序日志信息。log ... -
C# 开机启动
2010-05-13 17:41 1660C# winform程序设置开机 ... -
Base64编码的字符串与图片的转换 C#
2010-04-28 15:05 2847using System; using System.Col ...
相关推荐
多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄[整理].pdf
本文将对C#中的三种主要线程同步方法进行详细解释。 首先,`volatile`关键字是一种轻量级的线程同步手段。它指示编译器不要缓存变量的副本在每个线程的工作内存中,而是直接读写主内存中的值。这意味着所有线程都能...
以下是一些C#中实现线程同步的方法: 1. **volatile关键字**: `volatile`关键字用于标记一个字段,指示编译器不要缓存该字段的值,而是每次都从内存中读取。这在多处理器环境中特别有用,因为它确保所有线程都能...
以下是C#中常见的线程同步方法: 1. **volatile关键字** `volatile`关键字用于标记一个字段,表明该字段的值可能由其他线程随时更改。这使得编译器不会优化对这个字段的访问,确保每次读取都是从内存中获取最新值...
本文主要探讨了三种常见的线程同步方法:volatile关键字、lock关键字和System.Threading.Interlocked类。 首先,volatile关键字是一种轻量级的同步机制,适用于变量级别的同步。它指示编译器不要缓存变量值在工作...
\C#线程同步的几种方法\C#线程同步的几种方法
线程同步的方法多种多样,包括但不限于以下几种: 1. **Monitor**:C#的`Monitor`类提供了`Enter`和`Exit`方法,用于进入和退出临界区。当一个线程进入临界区后,其他试图进入的线程会被阻塞,直到该线程离开。这种...
线程同步是控制多个线程访问共享资源的一种方式,防止数据不一致和竞态条件的发生。本资源包“C#线程同步C#线程同步C#线程同步.rar”显然关注这一核心概念,它可能包含了各种线程同步的实例代码和解释。 1. **...
在C#编程中,线程同步与异步是并发编程中的关键概念,它们涉及到如何有效地管理多线程环境中的资源和执行顺序。本教程将深入探讨这两个概念,以帮助初学者更好地理解和应用。 同步编程是程序执行的一种方式,其中...
本文将探讨C#中常见的三种线程同步方法:Volatile关键字、lock关键字以及System.Threading.Interlocked类。 1. Volatile关键字: Volatile关键字用于标记变量,指示编译器和运行时系统不要将该变量缓存在寄存器或...
C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池相关资料C#线程同步及线程池...
以下是对C#中几种线程同步方法的详细说明: 1. **volatile关键字** volatile是一个轻量级的同步机制,它主要用来修饰字段,确保所有线程都能看到最新的值。volatile的作用是防止编译器优化,使得变量的读写操作...
Mutex(互斥锁)是一种高级同步机制,它允许只有一个线程访问共享资源,确保同一时间只有一个线程执行特定代码段。在C#中,Mutex类提供了WaitOne()和ReleaseMutex()方法,前者用于获取锁,后者用于释放锁。如果一个...
在C#编程中,多线程技术是一种提升应用程序性能的重要手段。它允许程序同时执行多个独立的任务,从而充分利用多核处理器的优势。线程池是一种管理线程资源的有效机制,而线程同步则是确保多线程间正确交互的关键概念...
因此,为了避免这种情况,开发者通常采用以下几种线程同步机制: 1. **阻塞**: - `Sleep` 方法会让当前线程进入阻塞状态,指定一段时间内不会占用CPU资源。 - `Join` 方法用于等待另一个线程完成执行。调用线程...
- 通过C#的委托和`Invoke/BeginInvoke`方法,我们可以在子线程中安全地更新UI,避免了线程同步问题和异常。 - 异步编程模型如`Task`和`async/await`提供了更现代、更简洁的多线程编程方式。 - 在实际开发中,应...
本文将深入探讨如何在C#中实现多线程同步并发操作,这不仅对于提高软件性能至关重要,也是高级程序员必须掌握的核心技能之一。 ### C#中的多线程同步并发操作 多线程编程可以极大地提高CPU的利用率,特别是在处理I...