标签:
3、ReaderWriterLock 类
ReaderWriterLock定义了实现单写程序和多写程序语义的锁。ReaderWriterLock类中4个主要的方法
? AcquireReacJerLock():获得-个读程序锁,超时值使用一个整数或一个 TimeSpan。
? AcquireWiiterLock(): 获得一个写程序锁,超时值使用一个整数或一个 TimeSpan。
? ReleaseReaderLock():释放读程序锁。
? ReleaseWriterLock(): 释放写程序锁。
一个线程可以持有读线程锁或写线程锁,但是不能同时持有两者。
Imports System.Threading Namespace AReadWriteLock Public Class ReadWrite Private rwl As ReaderWriterLock Private x As Integer Private y As Integer Public Sub New() rwl = New ReaderWriterLock() End Sub Public Sub ReadInts(ByRef a As Integer, ByRef b As Integer) rwl.AcquireReaderLock(Timeout.Infinite) Try a = x b = y Finally rwl.ReleaseReaderLock() End Try End Sub Public Sub WriteInts(ByVal a As Integer, ByVal b As Integer) rwl.AcquireWriterLock(Timeout.Infinite) Try x = a y = b Console.WriteLine(" x=" & x & " y=" & y & " ThreadID=" & Thread.CurrentThread.GetHashCode.ToString) Finally rwl.ReleaseWriterLock() End Try End Sub End Class Public Class RWApp Private rw As New ReadWrite Public Overloads Shared Sub Main(ByVal args() As String) Dim e As New RWApp() Dim wt1 As New Thread(New ThreadStart(AddressOf e.Write)) wt1.Start() Dim wt2 As New Thread(New ThreadStart(AddressOf e.Write)) wt2.Start() Dim rt1 As New Thread(New ThreadStart(AddressOf e.Read)) rt1.Start() Dim rt2 As New Thread(New ThreadStart(AddressOf e.Read)) rt2.Start() Console.ReadLine() End Sub Private Sub Write() Dim a As Integer = 10 Dim b As Integer = 11 Console.WriteLine("=== Write ID:" & Thread.CurrentThread.GetHashCode.ToString) For i As Integer = 0 To 2 rw.WriteInts(a, b) a += 1 b += 1 Thread.Sleep(1000) Next i End Sub Private Sub Read() Dim a As Integer = 10 Dim b As Integer = 11 Console.WriteLine("=== Read ID:" & Thread.CurrentThread.GetHashCode.ToString) For i As Integer = 0 To 2 rw.ReadInts(a, b) Console.WriteLine("For i=" & i & " a=" & a & ” b=” & b & " ThreadID=" & Thread.CurrentThread.GetHashCode.ToString) Thread.Sleep(1000) Next i End Sub End Class End Namespace线程的读锁或写锁同一时间只能有一个进入,结果如下:
Imports System.Threading Namespace NETThreadEvents Class AManualReset Shared LightSign As New ManualResetEvent(False) '1、无信号 Shared Sub main() Dim t(4) As Thread For i As Integer = 0 To 3 t(i) = New Thread(AddressOf RunOrWait) t(i).Start() Next 'LightSign.Set() '3、恢复有信号,线程甩开阻碍继续畅通向前运行 Console.Read() End Sub Public Shared Sub RunOrWait() Console.WriteLine("ID " & Thread.CurrentThread.GetHashCode.ToString & " waiting... ") LightSign.WaitOne() '2、无信号时线程挂起受阻,有信号则畅通 Console.WriteLine("ID " & Thread.CurrentThread.GetHashCode.ToString & "Running... not blocked!") End Sub End Class End Namespace说明:左图:1处设置为False,指示线程遇WaitOne受阻挂起,所以在RunOrWait()方法(2处)的WaitOne时就挂起了。中图:1处设置为True,线程畅通,2处WaiOne直接通过。右图:1处为false无信号,所以在2处受阻,但是由于3处加了一句Set,让信号亮起,前面挂起的恢复通过,没挂起当然也通过。图中可以看出10-12线程受阻,由于主线程Set恢复信号后,原挂起的11、12线程继续跑起,至于谁抢到CPU由OS决定。
Imports System.Threading Namespace NETThreadEvents Class AManualReset Shared LightSign As New AutoResetEvent(False) '1、无信号 Shared Sub main() Dim t(4) As Thread For i As Integer = 0 To 3 t(i) = New Thread(AddressOf RunOrWait) t(i).Start() Next LightSign.Set() '2,随机释放某一已经阻塞的线程(不是全部) Console.Read() End Sub Public Shared Sub RunOrWait() Console.WriteLine("ID " & Thread.CurrentThread.GetHashCode.ToString & " waiting... ") LightSign.WaitOne() Console.WriteLine("ID " & Thread.CurrentThread.GetHashCode.ToString & "Running... not blocked!") End Sub End Class End Namespace说明:Set后,仅将一个线程变成True,所以 ID9线程通过了,ID12仍然阻塞.
Imports System.Threading Namespace AMutex Class NETMutex Private Shared myMutex As Mutex Public Shared Sub Main() myMutex = New Mutex(True, "Magic") Dim nm As New NETMutex Dim t As New Thread(New ThreadStart(AddressOf nm.Run)) t.Start() Dim ID As String = Thread.CurrentThread.GetHashCode.ToString Console.WriteLine("ID:" & ID & " main thread will sleep for 3 seconds...") Thread.Sleep(3000) Console.WriteLine("ID:" & ID & ” main thread Woke Up") myMutex.ReleaseMutex() '1、释放互斥锁(让线程t中3处得到锁,以便向下运行) Console.WriteLine("ID:" & ID & " main Before WaitOne") myMutex.WaitOne() '2、阻塞,直到再次得到互斥锁(线程t中4处释放锁) Console.WriteLine("ID:" & ID & " main Lock. owned by Main Thread") Console.ReadLine() End Sub Public Sub Run() Dim ID As String = Thread.CurrentThread.GetHashCode.ToString Console.WriteLine("ID:" & ID & " t_thread In Run method") myMutex.WaitOne() '3、阻塞线程t,直到得到互斥锁),1外释放后,这里通畅向下 Console.WriteLine("ID:" & ID & " t_thread will sleep for 6 seconds") Thread.Sleep(6000) Console.WriteLine("ID:" & ID & " t_thread end of Run method") myMutex.ReleaseMutex() '4、此处必须释放锁,否则2处会无限等待锁(最后抛出异常) End Sub End Class End Namespace说明: 主线程创建互斥锁后,拥有该锁,等待3秒后在1处释放锁,以便让线程t拥有锁后(3处)继续向下运行,直到释放锁(4处),释放后主线程马上得到锁并在阻塞的2处继续向下运行。4处必须释放原因:MSDN: 在桌面的 .NET 中,如果没有线程拥有互斥体,则互斥体的状态为终止并将在下一个获取互斥体的线程中引发 AbandonedMutexException。
Interlocked可以为多个线程共享的变量提供原子操作:
Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。
Interlocked.Decrement 以原子操作的形式递减指定变量的值并存储结果。
Interlocked.Add 以原子操作的形式,添加两个整数并用两者的和替换第一个整数
注意:Intelocked原子操作锁定的是某一个值,仅在类似上面三句中生效,越过此句原子操作失效。
Imports System.Threading Namespace AInterLocker Class WinterLocked Public a As New ManualResetEvent(False) Private i As Integer = 5 Public Sub Run(ByVal s As Object) Interlocked.Increment(i) '2、原子操作递增 Console.WriteLine(Thread.CurrentThread.GetHashCode.ToString & " " & i) Thread.Sleep(500) 'Console.WriteLine(Thread.CurrentThread.GetHashCode.ToString & " completed") ‘3、非原子操作 End Sub Public Function GetValue() As Integer Return i End Function End Class Public Class MainApp Public Shared Sub Main() Dim mR As New ManualResetEvent(False) Dim wL As New WinterLocked For i As Integer = 1 To 10 '1、线程池排队 ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf wL.Run), 2) Next i mR.WaitOne(3000, True) '在3秒后退出同步域 Console.WriteLine("Result of 10 times is " & wL.GetValue) Console.ReadLine() End Sub End Class End Namespace说明:下面左右两图都是上面的结果,特别是左图,为啥会出现两个11,而少了10呢?首先确认10个线程进入后是进行了原子操作,每个线程增加1,因为10个线程的结果都是15(=5+10),因为原子操作仅在2处,过了此句后面的都不是原子操作。细节为:A线程原子锁定i(=9),然后增加1(i=10),后而退出原子操作马上要执行后一句提取i值(但还没显示),这里B线程切换进来,原子锁定i并对i增加1(i=10+1=11),然后原子操作退出并提取i值到B线程中。注意A、B线程提取的i值都是11,故显示的都是11,至于中间的12则是在输出过程中一样是要花费时间的,被另一线程C切入并提取i值12,并于B线程前输出。在3处增加一句显示i的结果,上面的效果将更加明显。
ThreadStaticAttribute 类
带有ThreadStaticAttribute 的Shared变量,对每个访问变量的线程都会有一个同一变量的单独副本。意味着如果一个线程修改了变量,另一个访问变量的线程就不能看到这些变化(包括主线程)。这种行为是有背于Shared变量的默认行为的。用处比如web应用中,每个请求都是一个独立的线程,如果我们希望将一个值作为静态字段全局使用,同时又不想影响其他用户,这时候一般我们是使用Session的。
Imports System.Threading Namespace TestShared Class AThreadStatic <ThreadStatic> Public Shared x As Integer '1、共享变量,各线程分别有副本x Public Shared y As Integer = 1 '2、共享变量,各线程无副本 Public Sub Run() For i As Integer = 1 To 5 Dim id As String = Thread.CurrentThread.GetHashCode.ToString x += 1 y += 1 Console.WriteLine("i=" & i & “ ThreadID=" & id & " x=" & x & " y=" & y) Thread.Sleep(1000) '3.共5次循环,花时5秒 Next i End Sub End Class Public Class MainApp Public Shared Sub Main() Dim tS As New AThreadStatic Dim tl As New Thread(New ThreadStart(AddressOf tS.Run)) Dim t2 As New Thread(New ThreadStart(AddressOf tS.Run)) tl.Start() t2.Start() Thread.Sleep(3500) '4、在3.5秒后,看一下类中共享变量值 Console.WriteLine("Main thread get value1:" & AThreadStatic.x & " " & AThreadStatic.y) Thread.Sleep(4000) '5、又4秒后,看一下类中共享变量值 Console.WriteLine("Main thread get value2:" & AThreadStatic.x & " " & AThreadStatic.y) Console.ReadLine() End Sub End Class End Namespace说明:x被标注后,在两个线程中将分别生成各自的x的副本(并不影响原类的值),所以在4处可以看到原类中x仍为0,但y没被标注,所以值是变化的。最后的结果(5处),也可以看出始终x没被修改为0(仅在各自的线程中修改其副本),y是修改的为11。
Imports System.Threading Namespace DeadLock Class DL Private field_1 As Integer = 0 Private field_2 As Integer = 0 Private lock_1 As Object = New Integer(1) {} Private lock_2 As Object = New Integer(1) {} Public Sub first(ByVal val As Integer) SyncLock lock_1 Console.WriteLine("First:Acquired lock_1:" & Thread.CurrentThread.GetHashCode.ToString + " Now Sleeping") Thread.Sleep(1000) SyncLock lock_2 Console.WriteLine("First:Acquired lock_2:" & Thread.CurrentThread.GetHashCode.ToString) field_1 = val field_2 = val End SyncLock End SyncLock End Sub Public Sub second(ByVal val As Integer) SyncLock lock_2 Console.WriteLine("Second:Acquired lock_2:" & Thread.CurrentThread.GetHashCode.ToString) SyncLock lock_1 Console.WriteLine("Second:Acquired lock I:" & Thread.CurrentThread.GetHashCode().ToString) field_1 = val field_2 = val End SyncLock End SyncLock End Sub End Class Public Class MainApp Private d As New DL() Public Shared Sub Main() Dim m As New MainApp Dim tl As New Thread(New ThreadStart(AddressOf m.Run1)) tl.Start() Dim t2 As New Thread(New ThreadStart(AddressOf m.Run2)) t2.Start() Console.ReadLine() End Sub Public Sub Run1() d.first(10) End Sub Public Sub Run2() d.second(10) End Sub End Class End Namespace说明:两个线程都分别拥有锁,还期待对方向的锁,都处于等待对方的锁,于是就死锁了。
标签:
原文地址:http://blog.csdn.net/dzweather/article/details/51635736