看下组织结构:

System.Object
  System.MarshalByRefObject
    System.Threading.WaitHandle
      System.Threading.Mutex
      System.Threading.Semaphore
      System.Threading.EventWaitHandle
        System.Threading.ManualResetEvent

        System.Threading.AutoResetEvent

System.Object

  System.Threading.Interlocked
  System.Threading.Monitor

  System.Threading.ReaderWriterLock

1, lock 关键字其实就是对 Monitor 类的 Enter()和 Exit()方法的封装。通过 try......catch......finally 语句块确保在 lock 语句块结束后执行 Monitor.Exit()方法,释放互斥锁。下面2段代码等价:

lock(locker)
{
//do something
}
Monitor.Enter(locker);
try
{
// do something
}
finally
{
Monitor.Exit(locker);
}

2,

Monitor类通过向单个线程授予对象锁来控制对对象的访问。对象锁提供限制访问临界区的能力。当一个线程拥有对象的锁时,其他任何线程都不能获取该锁。还可以使用 Monitor 来确保不会允许其他任何线程访问正在由锁的所有者执行的应用程序代码节,除非另一个线程正在使用其他的锁定对象执行该代码。通过对 lock 关键字的分析我们知道,lock 就是对 Monitor 的 Enter 和 Exit 的一个封装,而且使用起来更简洁,因此 Monitor 类的 Enter()和 Exit()方法的组合使用可以用 lock 关键字替代。 
   Monitor 类的常用方法: 
        TryEnter(): 
            能够有效的解决长期死等的问题,如果在一个并发经常发生,而且持续时间长的环境中使用 TryEnter,可以有效防止死锁或者长时间的等待。比如我们可以设置一个等待时间 bool gotLock = Monitor.TryEnter(myobject,1000),让当前线程在等待 1000 秒后根据返回的 bool 值来决定是否继续下面的操作。

Wait() :

释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的更改。 
        Pulse(): 
        PulseAll(): 
            向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。注意:Pulse、PulseAll 和 Wait 方法必须从同步的代码块内调用。

       static object locker = new object();
static bool isHave = false; static void Produce()
{
lock (locker)
{
while (true)
{
//如果已有产品,则等待消费完成
if (isHave)
Monitor.Wait(locker);
Console.WriteLine("生产一个");
Thread.Sleep();
isHave = true;
Monitor.Pulse(locker);
}
}
}
static void Consume()
{
lock (locker)
{
while (true)
{
//如果没有产品,则等待生产完成
if (!isHave)
Monitor.Wait(locker);
Console.WriteLine("消费一个");
Thread.Sleep();
isHave = false;
Monitor.Pulse(locker);
}
}
}

在main函数中调用:

            new Thread(Produce).Start();
new Thread(Consume).Start();

3, Mutex互斥体

public class Test
{
// Create a new Mutex. The creating thread does not own the
// Mutex.
private static Mutex mut = new Mutex(); public static void MyThreadProc()
{
for (int i = ; i < ; i++)
{
UseResource();
}
} // This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
mut.WaitOne(); Console.WriteLine("{0} has entered the protected area",
Thread.CurrentThread.Name); // Place code to access non-reentrant resources here. // Simulate some work.
Thread.Sleep(); Console.WriteLine("{0} is leaving the protected area\r\n",
Thread.CurrentThread.Name); // Release the Mutex.
mut.ReleaseMutex();
}
}
Test test = new Test();
for (int i = ; i < ; i++)
{
Thread myThread = new Thread(new ThreadStart(Test.MyThreadProc));
myThread.Name = String.Format("Thread{0}", i + );
myThread.Start();
}

mutex还可以判断系统是否已经有一个进程存在。

4,Semaphore 信号量

static Semaphore sph = new Semaphore(, );
static void TProc()
{
while (true)
{
if (sph.WaitOne(, false))
{
try
{
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":enter");
Thread.Sleep();
}
finally
{
sph.Release();
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":exit");
}
}
else
{
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":time out");
}
}
}
Thread t = null;
for (int i = ; i < ; i++)
{
t = new Thread(TProc);
t.Name = i.ToString();
t.Start();
}
Console.WriteLine("main sleep 4s");
Thread.Sleep();
sph.Release();

5,Interlocker类为多个线程共享的变量提供原子操作,它是一个静态类,主要的成员方法如下:
Add:以原子操作的形式,添加两个整数并用两者的和替换第一个整数。
Exchange:以原子操作的形式将变量设置为指定的值,并返回先前值
CompareExchange:比较两个值是否相等,如果相等,则替换其中一个值
Equals:确定两个Object 实例是否相等
Increment:以原子操作的形式递增指定变量的值并存储结果
Decrement:以原子操作的形式递减指定变量的值并存储结果
Read:返回一个以原子操作形式加载的 64 位值

Interlocked.CompareExchange(ref obj, new object(), null);

6, ReaderWriterLock

static ReaderWriterLock rwLock = new ReaderWriterLock();
static object locker = new object();
static void Main(string[] args)
{
Thread t = null;
for(int i = ; i < ;i++)
{
t = newThread(Writer);
t.Name =i.ToString();
t.Start();
}
for(int i = ; i<;i++)
{
t = newThread(Reader);
t.Name =i.ToString();
t.Start();
}
Console.ReadLine();
}
static void Writer()
{
while(true)
{
try
{
rwLock.AcquireWriterLock();
Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString());
try
{
Thread.Sleep();
}
finally
{
rwLock.ReleaseWriterLock();
Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " is exit");
}
}
catch(ApplicationException)
{
Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " wait time out");
}
}
}
static void Reader()
{
while (true)
{
rwLock.AcquireReaderLock(-);
Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString());
try
{
Thread.Sleep();
}
finally
{
Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is exit");
rwLock.ReleaseReaderLock();
}
}
}

7,AutoResetEvent 自动重置事件

在构造事件对象时需要指定initialState参数是True还是False,以指示事件的初始状态是有信号还是无信号

当一个自动重置事件得到信号时,等待该事件的线程中只有一个线程变为可调度线程,当手动重置对象得到信号时,等待该事件的所有线程均变为可调度线程

class Example
{
private static AutoResetEvent event_1 = new AutoResetEvent(true);
private static AutoResetEvent event_2 = new AutoResetEvent(false); static void Main()
{
Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
"The threads wait on AutoResetEvent #1, which was created\r\n" +
"in the signaled state, so the first thread is released.\r\n" +
"This puts AutoResetEvent #1 into the unsignaled state.");
Console.ReadLine(); for (int i = ; i < ; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(); for (int i = ; i < ; i++)
{
Console.WriteLine("Press Enter to release another thread.");
Console.ReadLine();
event_1.Set();
Thread.Sleep();
} Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
for (int i = ; i < ; i++)
{
Console.WriteLine("Press Enter to release a thread.");
Console.ReadLine();
event_2.Set();
Thread.Sleep();
} // Visual Studio: Uncomment the following line.
//Console.Readline();
} static void ThreadProc()
{
string name = Thread.CurrentThread.Name; Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
event_1.WaitOne();
Console.WriteLine("{0} is released from AutoResetEvent #1.", name); Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
event_2.WaitOne();
Console.WriteLine("{0} is released from AutoResetEvent #2.", name); Console.WriteLine("{0} ends.", name);
}
}

8, ManualResetEvent 手动重置事件

public class Example
{
// mre is used to block and release threads manually. It is
// created in the unsignaled state.
private static ManualResetEvent mre = new ManualResetEvent(false); static void Main()
{
Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n"); for(int i = ; i <= ; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
} Thread.Sleep();
Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
"\nto release all the threads.\n");
Console.ReadLine(); mre.Set(); Thread.Sleep();
Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
"\ndo not block. Press Enter to show this.\n");
Console.ReadLine(); for(int i = ; i <= ; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
} Thread.Sleep();
Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
"\nwhen they call WaitOne().\n");
Console.ReadLine(); mre.Reset(); // Start a thread that waits on the ManualResetEvent.
Thread t5 = new Thread(ThreadProc);
t5.Name = "Thread_5";
t5.Start(); Thread.Sleep();
Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
Console.ReadLine(); mre.Set(); // If you run this example in Visual Studio, uncomment the following line:
//Console.ReadLine();
} private static void ThreadProc()
{
string name = Thread.CurrentThread.Name; Console.WriteLine(name + " starts and calls mre.WaitOne()"); mre.WaitOne(); Console.WriteLine(name + " ends.");
}
}

9, .NET 在一些集合类,如 Queue、ArrayList、HashTable 和 Stack,已经提供了一个供 lock 使用的对象 SyncRoot。

Queue q = new Queue();
lock (q.SyncRoot)
{
foreach (object item in q)
{
//do something
}
}

参考资料:http://blog.csdn.net/zzy7075/article/details/29842165

C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEvent的更多相关文章

  1. 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁

    当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...

  2. C# 多线程(lock,Monitor,Mutex,同步事件和等待句柄)

    本篇从 Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler 的类关系图开始,希望通过本篇的介绍能对常见的线程同步方法有一个整体的认识,而 ...

  3. 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)

    本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...

  4. C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)

    本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...

  5. 线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步

    假设多个线程共享一个静态变量,如果让每个线程都执行相同的方法每次让静态变量自增1,这样的做法线程安全吗?能保证自增变量数据同步吗?本篇体验使用lock语句块和Interlocked类型方法保证自增变量 ...

  6. 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

    [源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...

  7. C#使用Monitor类、Lock和Mutex类进行多线程同步

    在多线程中,为了使数据保持一致性必须要对数据或是访问数据的函数加锁,在数据库中这是很常见的,但是在程序中由于大部分都是单线程的程序,所以没有加锁的必要,但是在多线程中,为了保持数据的同步,一定要加锁, ...

  8. C# 异步锁 await async锁,lock,Monitor,SemaphoreSlim

    异步方法内无法使用Monitor 和lock 所以只能用System.Threading.SemaphoreSlim了 //Semaphore (int initialCount, int maxim ...

  9. lock了mutex的线程退出了却没有unlock时会怎么样?

    https://stackoverflow.com/questions/4424193/what-happens-to-mutex-when-the-thread-which-acquired-it- ...

随机推荐

  1. Visual Studio 2010的MSDN帮助文档离线使用

    如果没有在安装vs过程中安装帮助,也可通过Visual Studio帮助菜单中的Manage Help Settings来对帮助进行设置或安装. 可以选择从磁盘安装内容,如果选择从磁盘安装可能会要求提 ...

  2. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

  3. ASP.NET Core HTTP 管道中的那些事儿

    前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...

  4. 在Ubuntu 16.10安装mysql workbench报未安装软件包 libpng12-0错误

    1.安装mysql workbench,提示未安装软件包 libpng12-0 下载了MySQL Workbench 6.3.8   在安装的时候报错: -1ubu1604-amd64.deb 提示: ...

  5. JavaScript之链式结构序列化

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  6. C#多线程之线程同步篇2

    在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...

  7. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  8. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  9. Maven 整合FreeMarker使用

    pom.xml <!-- freemarker jar --> <dependency> <groupId>org.freemarker</groupId&g ...

  10. Take into Action!

    很久没有认真地写文字了. 刚毕业一两年断断续续在csdn上写过一些当时的工作记录,然后没有坚持下去.有时候是觉得自己不牛,记录的东西旁人看起来也许不值一提:有时候觉得结婚生娃了,然后时间不够用(确实是 ...