C#各種同步辦法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEv。本站提示廣大學習愛好者:(C#各種同步辦法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEv)文章只能為提供參考,不一定能成為您想要的結果。以下是C#各種同步辦法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEv正文
看下組織構造:
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
}
View Code

Monitor.Enter(locker);
try
{
// do something
}
finally
{
Monitor.Exit(locker);
}
View Code
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(1000);
isHave = true;
Monitor.Pulse(locker);
}
}
}
static void Consume()
{
lock (locker)
{
while (true)
{
//假如沒有產品,則等候消費完成
if (!isHave)
Monitor.Wait(locker);
Console.WriteLine("消費一個");
Thread.Sleep(500);
isHave = false;
Monitor.Pulse(locker);
}
}
}
View Code
在main函數中調用:

new Thread(Produce).Start();
new Thread(Consume).Start();
View Code
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 = 0; i < 2; 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(500);
Console.WriteLine("{0} is leaving the protected area\r\n",
Thread.CurrentThread.Name);
// Release the Mutex.
mut.ReleaseMutex();
}
}
View Code

Test test = new Test();
for (int i = 0; i < 3; i++)
{
Thread myThread = new Thread(new ThreadStart(Test.MyThreadProc));
myThread.Name = String.Format("Thread{0}", i + 1);
myThread.Start();
}
View Code
mutex還可以判別零碎能否曾經有一個進程存在。
4,Semaphore 信號量

static Semaphore sph = new Semaphore(0, 3);
static void TProc()
{
while (true)
{
if (sph.WaitOne(500, false))
{
try
{
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":enter");
Thread.Sleep(1000);
}
finally
{
sph.Release();
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":exit");
}
}
else
{
Console.WriteLine("thread" + Thread.CurrentThread.Name + ":time out");
}
}
}
View Code

Thread t = null;
for (int i = 0; i < 2; i++)
{
t = new Thread(TProc);
t.Name = i.ToString();
t.Start();
}
Console.WriteLine("main sleep 4s");
Thread.Sleep(4000);
sph.Release(2);
View Code
5,Interlocker類為多個線程共享的變量提供原子操作,它是一個靜態類,次要的成員辦法如下:
Add:以原子操作的方式,添加兩個整數並用兩者的和交換第一個整數。
Exchange:以原子操作的方式將變量設置為指定的值,並前往先前值
CompareExchange:比擬兩個值能否相等,假如相等,則交換其中一個值
Equals:確定兩個Object 實例能否相等
Increment:以原子操作的方式遞增指定變量的值並存儲後果
Decrement:以原子操作的方式遞加指定變量的值並存儲後果
Read:前往一個以原子操作方式加載的 64 位值

Interlocked.CompareExchange(ref obj, new object(), null);View Code
6, ReaderWriterLock

static ReaderWriterLock rwLock = new ReaderWriterLock();
static object locker = new object();
static void Main(string[] args)
{
Thread t = null;
for(int i = 0; i < 2;i++)
{
t = newThread(Writer);
t.Name =i.ToString();
t.Start();
}
for(int i = 0; i<3;i++)
{
t = newThread(Reader);
t.Name =i.ToString();
t.Start();
}
Console.ReadLine();
}
static void Writer()
{
while(true)
{
try
{
rwLock.AcquireWriterLock(3000);
Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString());
try
{
Thread.Sleep(5000);
}
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(-1);
Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString());
try
{
Thread.Sleep(3000);
}
finally
{
Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is exit");
rwLock.ReleaseReaderLock();
}
}
}
View Code
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 = 1; i < 4; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(250);
for (int i = 0; i < 2; i++)
{
Console.WriteLine("Press Enter to release another thread.");
Console.ReadLine();
event_1.Set();
Thread.Sleep(250);
}
Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Press Enter to release a thread.");
Console.ReadLine();
event_2.Set();
Thread.Sleep(250);
}
// 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);
}
}
View Code
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 = 0; i <= 2; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(500);
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(500);
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 = 3; i <= 4; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(500);
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(500);
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.");
}
}
View Code
9, .NET 在一些集合類,如 Queue、ArrayList、HashTable 和 Stack,曾經提供了一個供 lock 運用的對象 SyncRoot。

Queue q = new Queue();
lock (q.SyncRoot)
{
foreach (object item in q)
{
//do something
}
}
View Code
參考材料:http://blog.csdn.net/zzy7075/article/details/29842165