看下组织结构:

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. In-Memory:内存优化表的事务处理

    内存优化表(Memory-Optimized Table,简称MOT)使用乐观策略(optimistic approach)实现事务的并发控制,在读取MOT时,使用多行版本化(Multi-Row ve ...

  2. Partition2:对表分区

    在SQL Server中,普通表可以转化为分区表,而分区表不能转化为普通表,普通表转化成分区表的过程是不可逆的,将普通表转化为分区表的方法是: 在分区架构(Partition Scheme)上创建聚集 ...

  3. ExtJS 4.2 业务开发(二)数据展示和查询

    本篇开始模拟一个船舶管理系统,提供查询.添加.修改船舶的功能,这里介绍其中的数据展示和查询功能. 目录 1. 数据展示 2. 数据查询 3. 在线演示 1. 数据展示 在这里我们将模拟一个船舶管理系统 ...

  4. Python-Jenkins API使用 —— 在后端代码中操控Jenkins

    最近在工作中需要用到在后台代码中触发Jenkins任务的构建,于是想到Jenkins是否有一些已经封装好的API类库提供,用于处理跟Jenkins相关的操作.下面就简单介绍下我的发现. Linux C ...

  5. PHP赋值运算

    1. 赋值运算:= ,意思是右边表达式的值赋给左边的运算数. $int1=10; $int1=$int1-6; //$int1=4 echo $int1,"<br>"; ...

  6. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  7. 原生js+css3实现图片自动切换,图片轮播

    运用CSS3transition及opacity属性 制作图片轮播动画 自己这两天根据用js来控制触发CSS3中transition属性,从而写出来的以CSS3动画为基础,js控制过程的图片轮播 运用 ...

  8. .NET面试题集锦②(Part 二)

    一.前言部分 文中的问题及答案多收集整理自网络,不保证100%准确,还望斟酌采纳. 1.实现产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复. ]; ArrayList my ...

  9. 在 Windows7 上按照 MySQL5.7

    在 Windows7 上按照 MySQL5.7 1.从官网下载最新版本的 MySQL,这里下载的是 mysql-5.7.17-win32: 2.将下载的 mysql-5.7.17-win32.zip ...

  10. 【一起学OpenFOAM】系列由来

    1 为什么要学习OpenFOAM 掐指算起来,接触CFD也差不多有十个年头了,其间一直使用的商用CFD软件,有Fluent.CFX.StarCCM+等,这些商用软件各有其优缺点,都能较好的解决常规的工 ...