C# 語言的多線程編程,完全是本科OS裡的知識
基本知識,無參數Thread和帶參數的Thread
Thread類的參數就是參數指針,可以傳入一個無參的函數。
如果要傳入帶參數的函數,先new一個ParameterizedThreadStart委托實例,帶參數的函數名作為它的參數。帶參數的函數必須且只能有一個object參數。參考下面的
ConterWithParam(object param)
復制代碼
static int iCnt = 0;
static readonly int N = 10000;
static void Main(string[] args)
{
Thread[] thrs = new Thread[N];
for (int i = 0; i < N; i++)
{
thrs[i] = new Thread(Counter);
thrs[i].Start();
}
for (int i = 0; i < N; i++)
{
thrs[i].Join();
}
Console.WriteLine(iCnt);
iCnt = 0;
ParameterizedThreadStart[] thrsp = new ParameterizedThreadStart[N];
object param = 2;
for (int i = 0; i < N; i++)
{
thrsp[i] = new ParameterizedThreadStart(ConterWithParam);
thrs[i] = new Thread(thrsp[i]);
thrs[i].Start(param);
}
for (int i = 0; i < N; i++)
{
//當NewThread調用Join方法的時候,MainThread就被停止執行,直到NewThread線程執行完畢
thrs[i].Join();
}
Console.WriteLine(iCnt);
}
static void Counter()
{
Thread.Sleep(100);
iCnt++;
//Console.WriteLine("finish iCnt++,now iCnt is " + iCnt);
}
static void ConterWithParam(object param)
{
Thread.Sleep(100);
int i = (int)param;
iCnt += i;
//Console.WriteLine("finish iCnt+"+i+",now iCnt is " + iCnt);
}
復制代碼
該例子輸出結果
2)互斥信號燈mutex
第一節的結果是不是有點奇怪。明明加了10000次,結果卻是9550.
帶參數的那個例子,一次加2,加10000次,應該是20000才對。結果卻是19678.
這是因為對全局變量的訪問iCnt出現了沖突。比如兩個線程同時取到了iCnt=0時的值,同時執行了i++,那麼iCnt的最後狀態肯定是1,而不是會2。為了讓iCnt得到正確的值。
我們引入互斥信號燈。
復制代碼
static int iCnt = 0;
static readonly int N = 10000;
static Mutex mut = new Mutex();
static void Main(string[] args)
{
Thread[] thrs = new Thread[N];
for (int i = 0; i < N; i++)
{
thrs[i] = new Thread(Counter);
thrs[i].Start();
}
for (int i = 0; i < N; i++)
{
thrs[i].Join();
}
Console.WriteLine(iCnt);
iCnt = 0;
ParameterizedThreadStart[] thrsp = new ParameterizedThreadStart[N];
object param = 2;
for (int i = 0; i < N; i++)
{
thrsp[i] = new ParameterizedThreadStart(ConterWithParam);
thrs[i] = new Thread(thrsp[i]);
thrs[i].Start(param);
}
for (int i = 0; i < N; i++)
{
//當NewThread調用Join方法的時候,MainThread就被停止執行,直到NewThread線程執行完畢
thrs[i].Join();
}
Console.WriteLine(iCnt);
}
static void Counter()
{
Thread.Sleep(10);
//鎖
mut.WaitOne();
iCnt++;
//釋放
mut.ReleaseMutex();
//Console.WriteLine("finish iCnt++,now iCnt is " + iCnt);
}
static void ConterWithParam(object param)
{
Thread.Sleep(10);
//鎖住
mut.WaitOne();
int i = (int)param;
iCnt += i;
//釋放
mut.ReleaseMutex();
//Console.WriteLine("finish iCnt+"+i+",now iCnt is " + iCnt);
}
復制代碼
本次執行結果
3) 同步信號燈Semaphore
用最經典的生產者-消費者來解釋。
復制代碼
static Semaphore sem = new Semaphore(0, 1);
static Semaphore sem2 = new Semaphore(0, 5);
static void Main(string[] args)
{
Console.WriteLine("消費者等生產者生產一個item");
Thread thConsumer = new Thread(Consume);
thConsumer.Start();
Thread thProductor = new Thread(Product);
thProductor.Start();
thConsumer.Join();
thProductor.Join();
Console.WriteLine(".............................");
Console.WriteLine("多並發的例子.....");
for (int i = 0; i < 10; i++)
{
Thread t1 = new Thread(Consume2);
t1.Start();
Thread t2 = new Thread(Product2);
t2.Start();
}//end for
}
static void Product()
{
Thread.Sleep(2000);
Console.WriteLine("Product an item...");
sem.Release();
}
static void Consume()
{
Thread.Sleep(1000);
Console.WriteLine("Consumer is waiting an item...");
sem.WaitOne();
Console.WriteLine("Consumer get an item...");
}
static void Product2()
{
Thread.Sleep(1000);
Console.WriteLine("Product an item...");
sem2.Release();
}
static void Consume2()
{
Thread.Sleep(1000);
Console.WriteLine("Consumer is waiting an item...");
sem2.WaitOne();
Console.WriteLine("Consumer get an item...");
}