看下组织结构:

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. 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代

    2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...

  2. 通过adb方式给安卓手机截图的cmd批处理文件

    @echo off rem  通过adb方式截图rem  需要安装adb ,一般安装了android sdk 默认带了adb ,路径为sdk目录的android-sdk\platform-toolsr ...

  3. C++内存对齐总结

    大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...

  4. MIP 官方发布 v1稳定版本

    近期,MIP官方发布了MIP系列文件的全新v1版本,我们建议大家尽快完成升级. 一. 我是开发者,如何升级版本? 对于MIP页面开发者来说,只需替换线上引用的MIP文件为v1版本,就可以完成升级.所有 ...

  5. SQLSERVER走起 APP隆重推出

    SQLSERVER走起 APP隆重推出 为方便大家查看本微信公众以前推送的文章,QQ群里面的某位SQLSERVER重度爱好者开发了<SQLSERVER走起>的APP 以供大家一起交流 网页 ...

  6. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. [开发笔记]yum错误

    yum 错误TypeError: rpmdb open failed 解决办法 是因为RPM数据库出现损坏导致的,它导致所有的软件的升级.安装甚至是删除都会出现问题,终端出现乱码,YUMEX也用不成, ...

  8. iOS UITableView 与 UITableViewController

    很多应用都会在界面中使用某种列表控件:用户可以选中.删除或重新排列列表中的项目.这些控件其实都是UITableView 对象,可以用来显示一组对象,例如,用户地址薄中的一组人名.项目地址. UITab ...

  9. Java compiler level does not match解决方法

    从别的地方导入一个项目的时候,经常会遇到eclipse/Myeclipse报Description  Resource Path Location Type Java compiler level d ...

  10. UVA, 10336 Rank the Languages

    难点在于:递归函数和输出: #include <iostream> #include <vector> #include <algorithm> #include ...