我是剛剛接觸多線程程序,10幾頁書弄了不短的時間,下面是自己的一點體會:
對於剛接觸多線程編程的,調試多線程程序先要把線程和同步的定義搞明白,理解透了。多線程程序調試的時候是和非多線程程序不同的,兩次調試的輸出結果可能會不同,這是很正常的,就是運行兩次輸出也有可能不一樣(不過幾率不大)。還有就是我們的單步調試並不能精確的模擬程序非調試時的運行軌跡,有一部分是要我們自己去想象的。多線程的魅力也在於此。調試的時候要耐住性子,多寫點輸出句,慢慢分析,才能得到更多的東西。
進程與線程簡介
進程(Process)是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,是系統進行資源分配和調度的一個獨立單位。程序只是一組指令的有序集合,它本身沒有任何運行的含義,只是一個靜態實體。而進程則不同,它是程序在某個數據集上的執行,是一個動態實體。它因創建而產生,因調度而運行,因等待資源或事件而被處於等待狀態,因完成任務而被撤消,反映了一個程序在一定的數據集上運行的全部動態過程。進程用來描述程序的執行過程而且可以作為共享資源的基本單位。
線程(Thread)是進程的一個實體,是CPU調度和分派的基本單位。線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。線程是進程的執行單元。當進程被初始化後,主線程就被創建了。對於絕大多數的應用程序來說,通常僅要求有一個主線程。盡管如此進程也可以創建額外的線程。線程是獨立運行的,它且並不知道進程中還有其他線程存在。線程的執行是搶占式的,也就是說,當前運行的線程在任何時候都可能被掛起,以便另外一個線程可以運行。
線程和進程的關系是:線程是屬於進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間,當進程退出時該進程所產生的線程都會被強制退出並清除。線程可與屬於同一進程的其它線程共享進程所擁有的全部資源,但是其本身基本上不擁有系統資源,只擁有一點在運行中必不可少的信息(如程序計數器、一組寄存器和棧)。
實例代碼:Mutex類
Mutex(互斥體)提供對一個進程的多個線程執行同步控制的能力,還用於對多個進程的不同線程實施同步控制。他的功能是阻止多個線程對一個共享資源並發訪問。
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Collections.Generic;
using System.Text;
namespace MutexSample
...{
class Program
...{
static int sharedNumber = 42;
static Mutex localMut = new Mutex();
static bool isNew;
//out 表示通過引用來傳遞。這與 ref 類似,不同在於 ref 要求變量必須在傳遞之前初始化。若要使用 out 參數,方法定義和調用方法都必須顯式使用 out
//參數1指示調用線程是否應擁有互斥體的初始所屬權、參數2作為互斥體名,參數3方法返回時指示調用線程是否被授予互斥體的初始所屬權
static Mutex globalMut = new Mutex(true, "Mutex Demo Global Mutex", out isNew);
static void Main(string[] args)
...{
if (!isNew)
...{
Console.WriteLine("This application is already running, shutting additional instance down.");
return;
}
// spin off a bunch of threads to perform //英語學習時間 spin off:創造新的事物而不影響原物的大小[穩定性]
// processing on a shared resource
Thread[] workers = new Thread[20];
for (int i = 0; i < 20; i++)
...{
Thread worker = new Thread(new ThreadStart(DoWork));
workers[i] = worker;
worker.Start();
}
foreach (Thread workerThread in workers)
workerThread.Join();
Console.WriteLine("All work finished, new value of shared resource is {0}", sharedNumber);
Console.ReadLine();
globalMut.ReleaseMutex();
}
//線程組中線程的共享代碼
static void DoWork()
...{
// sit and wait until its OK to Access
// the shared resource
//WaitOne()使互斥體等待一個(共享資源沒被占用或釋放的)信號(阻止當前進程),使訪問共享資源而不必擔心同步問題
localMut.WaitOne();
// modify shared resource
// multiple lines of code to modify
// to show consistent state of data
// within Mutex-protected block
Console.WriteLine("Accessing protected resource...");
sharedNumber += 2;
Console.WriteLine(sharedNumber);
sharedNumber -= 1;
Console.WriteLine(sharedNumber);
localMut.ReleaseMutex();
}
}
}
//大尾巴狼注:當訪問某共享資源的線程獲得一個互斥體時,所以隨後想訪問改共享資源的互斥體必須等待第一個線程釋放該共享資源。這項功能不是Mutex自動完成的要通過調用Mutex中的一些方法實現,例如:WaitOne()
實例代碼:ReadWriteLock類
它允許一個線程中的代碼讀取共享時數據,單不需要創建一個同步代碼塊,也不會阻塞其他線程對該共享資源的讀請求。ReadWriteLock只阻塞那些企圖更新共享資源的請求,或者故意要在讀取共享資源時對其加鎖的請求。
using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;
namespace ReadWriteLockDemo
{
class Program
{
// shared resource here is a simple int
static int i = 0;
static int sharedResource = 42;
static int numTimeouts = 0;
static ReaderWriterLock rwl = new ReaderWriterLock();
static void Main(string[] args)
{
// Create 10 threads that want write Access
Thread[] writers = new Thread[10];
for (int i = 0; i < 10; i++)
{
Thread writeThread = new Thread(new ThreadStart(DoWrite));
writers[i] = writeThread;
writers[i].Start();
}
Console.WriteLine("1111111111111111");
// Create 40 threads that want read Access
Thread[] readers = new Thread[40];
for (int j = 0; j < 40; j++)
{
Thread readThread = new Thread(new ThreadStart(DoRead));
readers[j] = readThread;
readers[j].Start();
}
// wait till they''re all done
foreach (Thread writer in writers)
writer.Join();
foreach (Thread reader in readers)
reader.Join();
Console.WriteLine("All work finished, only {0} timeouts.", numTimeouts);
Console.ReadLine();
}
static void DoWrite()
{
try
{
rwl.AcquireWriterLock(100);//當超時就拋出異常,從而跳過部分代碼
try
{
Interlocked.Increment(ref sharedResource);//以原子操作的形式遞增指定變量的值並存儲結果,功能就是sharedResource++
Console.WriteLine("Inspecting shared value {0}", sharedResource);
Thread.Sleep(15);
}
finally
{
rwl.ReleaseWriterLock();
}
}
catch (ApplicationException ae)
{
Interlocked.Increment(ref numTimeouts);
}
static void DoRead()
{
try
{
rwl.AcquireReaderLock(100);
try
{
Console.WriteLine("Inspecting shared value {0}...輸出計數{1}", sharedResource,i++);
}
finally
{
rwl.ReleaseReaderLock();
}
}
catch (ApplicationException ae)
{
Interlocked.Increment(ref numTimeouts);
}
}
}
}
//大尾巴狼注:sharedResource+numTimeouts=52 這段代碼線程比較多還有時間間隔參數,不要迷惑:1個主線程,分出2個線程組逐個的分解分析才能明白。調試看起來比較迷糊,黃點跳躍的太多....... 代碼: Visual C# 2005 Unleashed