C# 線程使用
1.lock鎖定
建立一個類,代碼如下:
class Person
{
private readonly int RunCount = 10000;
private int RunCountA = 0;//A方法執行的次數
private int RunCountB = 0;//B方法執行的次數
private int RunCountC = 0;//總共方法執行的次數
private bool IsRunA = true;
public void DoWorkA() {
Console.WriteLine("DoWorkA...");
while (true)
{
if (RunCountA == RunCount || RunCountB == RunCount)
{
Console.WriteLine("DoWorkA:RunCountA:{0} RunCountB:{1} RunCountC:{2}", RunCountA, RunCountB, RunCountC);
break;
}
//lock (o)
//{
if (IsRunA)
{
RunCountA++;
RunCountC++;
IsRunA = !IsRunA;
}
//}
}
}
public void DoWorkB()
{
Console.WriteLine("DoWorkB...");
while (true)
{
if (RunCountA == RunCount || RunCountB == RunCount)
{
Console.WriteLine("DoWorkB:RunCountA:{0} RunCountB:{1} RunCountC:{2}", RunCountA, RunCountB, RunCountC);
break;
}
//lock (o)
//{
if (!IsRunA)
{
RunCountB++;
RunCountC++;
IsRunA = !IsRunA;
}
//}
}
}
private object o=new object();
}
調用代碼如下:
static void Main(string[] args)
{
Person p = new Person();
System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(p.DoWorkA));
System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(p.DoWorkB));
System.Threading.Thread t3 = new System.Threading.Thread(new System.Threading.ThreadStart(p.DoWorkB));
t3.Start();
System.Threading.Thread t4 = new System.Threading.Thread(new System.Threading.ThreadStart(p.DoWorkB));
t4.Start();
t1.Start();
t2.Start();
Console.ReadLine();
}
在沒有使用lock對象的時候,得出的結果如下:
可以看出。RunCountA!=RunCount ,RunCountC不等於RunCountA+RunCountB,這個就是對線程共享變量的問題。
下面加上lock鎖定,要鎖定,定義一個objct變量
再次執行代碼:
會得到我們期望的數值,介面如下:
2.使用mutex
定義:private Mutex mutex = new Mutex();
鎖定:mutex.WaitOne();從這裡開始的代碼變量是安全的。
釋放:mutex.ReleaseMutex();
把lock 去掉,用這2個語句代替。也能達到上面的效果。
3.Monitor是一個靜態類,提供靜態方法。
首先:定義一個object 對象,必須是object對象,否則會出錯。
if (Monitor.TryEnter(o))
{
Monitor.Enter(o);
if (!IsRunA)
{
RunCountB++;
RunCountC++;
IsRunA = !IsRunA;
}
Monitor.Exit(o);
}
Monitor.TryEnter(o) 是否能進入這塊區域
Monitor.Enter(o);鎖定區域
Monitor.Exit(o);釋放區域
4.Interlocked 提供原子鎖定,也是提供靜態方法
其中usingResource為int ,必須定義為private int usingResource = 0,因為第一次是從0開始。要和開始方法中的變量不同。
如果Interlocked.Exchange(ref usingResource, 1)是1則private int usingResource = 0,否則private int usingResource = 1
if (0 == Interlocked.Exchange(ref usingResource, 1))進入鎖定區域
Interlocked.Exchange(ref usingResource, 0); 釋放鎖定區域
Interlocked.Increment(ref safeInstanceCount);原子遞增,相當於 safeInstanceCount++
Interlocked.Decrement(ref safeInstanceCount);原子遞減,相當於 safeInstanceCount--
5.WaitCallback使用,允许线程通过发信号互相通信
如:此计算的格式为:result = first term + second term + third term,其中每项都要求使用计算出的基数进行预计算和最终计算
此類,需要調用ThreadPool這個進行護理。
5.1 定義幾個處理方法
AutoResetEvent[] autoEvents
autoEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};
初始狀態為運行狀態。
5.2 定義ManualResetEvent manualEvent;表示,是否能執行完這個線程,可以繼續執行下面的代碼
初始化為: manualEvent = new ManualResetEvent(false);
manualEvent.Reset();為線程結束,可以繼續下面的代碼
5.3使用ThreadPool線程池來執行線程
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateBase));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateFirstTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateSecondTerm));
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateThirdTerm));
5.4對於每一個方法 autoEvents[0].Set();表示第二個方法結束,可以釋放信號。
manualEvent.Set();是第一個方法結束,進入manualEvent處理中。
最後在manualEvent.Reset();方法后,將得到的結果進行處理。
6.ThreadPool系統提供的線程池,托管线程池中的线程为后台线程,每个进程都有一个线程池。线程池的默认大小为每个可用处理器有 25 个线程。
使用 SetMaxThreads 方法可以更改线程池中的线程数。線程池中的線程,是自動執行的。
6.1ThreadPool.QueueUserWorkItem
将方法排入队列以便执行。此方法在有线程池线程变得可用时执行。此方法,可以帶參數,可以傳遞給方法參數
ThreadPool.QueueUserWorkItem(
new WaitCallback(CalculateBase),"12");
7. LockCookie 单个编写器/多个阅读器语义的锁
7.1 ReaderWriterLock rwl = new ReaderWriterLock();定義鎖
7.2 rwl.AcquireReaderLock(timeOut);讀取鎖開始
rwl.ReleaseReaderLock();釋放讀取鎖。
7.3 LockCookie lc = rwl.UpgradeToWriterLock(timeOut);定義寫鎖
rwl.DowngradeFromWriterLock(ref lc);釋放寫鎖。