CountdownEvent主要是用來等待直到一定數量的執行緒完成。
以下範例有三個執行緒,但等待兩個完成後即可繼續往下執行。
程式碼如下:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
//等待一定數量完成才繼續往下執行,在這邊設定等待2個執行緒完成
static CountdownEvent _event = new CountdownEvent(2);
static void PerformOperation(string message,int seconds)
{
try
{
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine(message);
//發送信號計數+1
_event.Signal();
}
catch(System.ObjectDisposedException)
{
Console.WriteLine("CountdownEvent has disposed");
}
}
static void Main(string[] args)
{
Thread t1 = new Thread(() => { PerformOperation("operation 1 is completed.",2); });
t1.Name = "t1";
Thread t2 = new Thread(() => { PerformOperation("operation 2 is completed.", 4); });
t2.Name = "t2";
Thread t3 = new Thread(() => { PerformOperation("operation 3 is completed.", 12); });
t3.Name = "t3";
t1.Start();
t2.Start();
t3.Start();
//開始等待完成
_event.Wait();
Console.WriteLine("有兩個已完成!");
_event.Dispose();
Console.WriteLine("繼續往下執行...");
Console.ReadKey();
}
}
}
打印結果如下:
2019年3月21日 星期四
2019年3月11日 星期一
C# 執行緒(Thread)的AutoResetEvent及ManualResetEvent探討
AutoResetEvent及ManualResetEvent都是可以讓執行緒藉由發出訊號,與彼此進行通訊,控制執行緒暫停或繼續,就像高速公路上的閘道一樣,控制關閉或通行,初始的bool變量,來指明閘道的狀態,true表示可以通行、false表示不可通行。閘道主要有三個方法:WaitOne、Set和Reset。他們就像閘道一樣控制開關,控制執行緒暫停或繼續,Set()表示繼續、WaitOne表示暫停。而這兩者的主要差別在於:
AutoResetEvent
AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();
以下是程式碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
private static AutoResetEvent _guard1Event = new AutoResetEvent(false);
private static AutoResetEvent _guard2Event = new AutoResetEvent(false);
private static ManualResetEvent _gateEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
/** *******************
* Thread的AutoResetEvent機制
* ********************/
var t = new Thread(() => Process(10));
t.Start();
Console.WriteLine("1.Waiting for another thread completed its work.");
//等待通行信號
_guard2Event.WaitOne();
Console.WriteLine("5.First operation is completed.");
Thread.Sleep(TimeSpan.FromSeconds(5));
//發送信號通知正在等待的Thread工作已經完成
_guard1Event.Set();
Console.WriteLine("6.Second operation is Starting.");
//等待通行信號
_guard2Event.WaitOne();
Console.WriteLine("9.Second operation is completed.");
Console.ReadKey();
Console.WriteLine("---------------------------------");
/** *******************
* Thread的ManualResetEvent機制
* ********************/
var t1 = new Thread(() => TravelThroughGates("thread 1",5));
var t2 = new Thread(() => TravelThroughGates("thread 2", 7));
var t3 = new Thread(() => TravelThroughGates("thread 3", 9));
t1.Start();
t2.Start();
t3.Start();
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine($"the gates are open now.");
_gateEvent.Set();
Console.WriteLine($"the gates have been closed.");
_gateEvent.Reset();
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine($"the gates are open for a while.");
_gateEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"the gates have been closed.");
_gateEvent.Reset();
Console.ReadKey();
}
static void Process(int seconds)
{
Console.WriteLine("2.Start running");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("3.Work is done.");
//發送信號通知可通行
_guard2Event.Set();
Console.WriteLine("4.Waiting for a main thread completed its work.");
//等待信號主程序給通行信號
_guard1Event.WaitOne();
Console.WriteLine("7.Start second operation");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("8.Work is done.");
_guard2Event.Set();
}
static void TravelThroughGates(string threadName, int seconds)
{
Console.WriteLine($"{threadName} is falling asleep");
//開放通行
_gateEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{threadName} is waiting for gates to open");
//等待通行信號
_gateEvent.WaitOne();
Console.WriteLine($"{threadName} entered the gates");
}
}
}
這是執行結果:
AutoResetEvent
- 只會給一個執行緒發送訊號
- Set()後狀態設置會自動設置成false
ManualResetEvent
- 給所有執行續發送訊號
- Set()後狀態設置會設置成true,需要手動呼叫Reset()將狀態改為false,在狀態為true時候,WaitOne是沒有作用的
以下是程式碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
private static AutoResetEvent _guard1Event = new AutoResetEvent(false);
private static AutoResetEvent _guard2Event = new AutoResetEvent(false);
private static ManualResetEvent _gateEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
/** *******************
* Thread的AutoResetEvent機制
* ********************/
var t = new Thread(() => Process(10));
t.Start();
Console.WriteLine("1.Waiting for another thread completed its work.");
//等待通行信號
_guard2Event.WaitOne();
Console.WriteLine("5.First operation is completed.");
Thread.Sleep(TimeSpan.FromSeconds(5));
//發送信號通知正在等待的Thread工作已經完成
_guard1Event.Set();
Console.WriteLine("6.Second operation is Starting.");
//等待通行信號
_guard2Event.WaitOne();
Console.WriteLine("9.Second operation is completed.");
Console.ReadKey();
Console.WriteLine("---------------------------------");
/** *******************
* Thread的ManualResetEvent機制
* ********************/
var t1 = new Thread(() => TravelThroughGates("thread 1",5));
var t2 = new Thread(() => TravelThroughGates("thread 2", 7));
var t3 = new Thread(() => TravelThroughGates("thread 3", 9));
t1.Start();
t2.Start();
t3.Start();
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine($"the gates are open now.");
_gateEvent.Set();
Console.WriteLine($"the gates have been closed.");
_gateEvent.Reset();
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine($"the gates are open for a while.");
_gateEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"the gates have been closed.");
_gateEvent.Reset();
Console.ReadKey();
}
static void Process(int seconds)
{
Console.WriteLine("2.Start running");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("3.Work is done.");
//發送信號通知可通行
_guard2Event.Set();
Console.WriteLine("4.Waiting for a main thread completed its work.");
//等待信號主程序給通行信號
_guard1Event.WaitOne();
Console.WriteLine("7.Start second operation");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("8.Work is done.");
_guard2Event.Set();
}
static void TravelThroughGates(string threadName, int seconds)
{
Console.WriteLine($"{threadName} is falling asleep");
//開放通行
_gateEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{threadName} is waiting for gates to open");
//等待通行信號
_gateEvent.WaitOne();
Console.WriteLine($"{threadName} entered the gates");
}
}
}
這是執行結果:
2019年3月5日 星期二
C# 利用iTextSharp合併pdf
using iTextSharp.text;
using iTextSharp.text.pdf;
/// <summary>
/// 合併PDF
/// </summary>
/// <param name="fileList">被合併的文件集合</param>
/// <param name="outMergeFile">合併文件路徑</param>
/// <param name="iFlag">0:A4直印, 1:A4橫印</param>
public void MergePDFFiles(string[] fileList, string outMergeFile, int iFlag)
{
PdfReader reader;
Document document = new Document();
if (iFlag != 0)
{
document = new Document(iTextSharp.text.PageSize.A4.Rotate());
}
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outMergeFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage newPage;
for (int i = 0; i < fileList.Length; i++)
{
if (fileList[i] != null && fileList[i] != string.Empty)
{
reader = new PdfReader(fileList[i]);
int iPageNum = reader.NumberOfPages;
for (int j = 1; j <= iPageNum; j++)
{
document.NewPage();
newPage = writer.GetImportedPage(reader, j);
cb.AddTemplate(newPage, 0, 0);
}
}
}
document.Close();
}
/// <summary>
/// 合併PDF 自動判斷方向
/// </summary>
/// <param name="fileList">被合併的文件集合</param>
/// <param name="outMergeFile">合併文件路徑</param>
public void MergePDFFiles(string[] fileList, string outMergeFile)
{
int f = 0;
PdfReader reader = new PdfReader(fileList[f]);
Document document = new Document();
document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outMergeFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage newPage;
int rotation = 0;
for (int i = 0; i < fileList.Length; i++)
{
if (fileList[i] != null)
{
reader = new PdfReader(fileList[i]);
int iPageNum = reader.NumberOfPages;
for (int j = 1; j <= iPageNum; j++)
{
document.NewPage();
newPage = writer.GetImportedPage(reader, j);
rotation = reader.GetPageRotation(j);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(newPage, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(newPage, 1f, 0, 0, 1f, 0, 0);
}
}
}
}
}
using iTextSharp.text.pdf;
/// <summary>
/// 合併PDF
/// </summary>
/// <param name="fileList">被合併的文件集合</param>
/// <param name="outMergeFile">合併文件路徑</param>
/// <param name="iFlag">0:A4直印, 1:A4橫印</param>
public void MergePDFFiles(string[] fileList, string outMergeFile, int iFlag)
{
PdfReader reader;
Document document = new Document();
if (iFlag != 0)
{
document = new Document(iTextSharp.text.PageSize.A4.Rotate());
}
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outMergeFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage newPage;
for (int i = 0; i < fileList.Length; i++)
{
if (fileList[i] != null && fileList[i] != string.Empty)
{
reader = new PdfReader(fileList[i]);
int iPageNum = reader.NumberOfPages;
for (int j = 1; j <= iPageNum; j++)
{
document.NewPage();
newPage = writer.GetImportedPage(reader, j);
cb.AddTemplate(newPage, 0, 0);
}
}
}
document.Close();
}
/// <summary>
/// 合併PDF 自動判斷方向
/// </summary>
/// <param name="fileList">被合併的文件集合</param>
/// <param name="outMergeFile">合併文件路徑</param>
public void MergePDFFiles(string[] fileList, string outMergeFile)
{
int f = 0;
PdfReader reader = new PdfReader(fileList[f]);
Document document = new Document();
document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outMergeFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage newPage;
int rotation = 0;
for (int i = 0; i < fileList.Length; i++)
{
if (fileList[i] != null)
{
reader = new PdfReader(fileList[i]);
int iPageNum = reader.NumberOfPages;
for (int j = 1; j <= iPageNum; j++)
{
document.NewPage();
newPage = writer.GetImportedPage(reader, j);
rotation = reader.GetPageRotation(j);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(newPage, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(newPage, 1f, 0, 0, 1f, 0, 0);
}
}
}
}
}
2019年3月4日 星期一
C# 執行緒(Thread)的Mutex及Semaphore探討
Mutex
以下是 Mutex範例:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的Mutex機制
* ********************/
string mutexName = "互斥量";
using (var mutex = new Mutex(false, mutexName))
{
if (mutex.WaitOne(TimeSpan.FromSeconds(5), false))
{
Console.WriteLine("占用一下");
Console.ReadLine();
mutex.ReleaseMutex();
}
else
{
Console.WriteLine("我搶不到");
}
}
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
}
同時執行兩個Process時,第一個Process會看到占用一下,第二個Process會看到我搶不到,
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(3);
/// <summary>
/// 在上廁所
/// </summary>
/// <param name="seconds"></param>
static void Toilet(int seconds)
{
Console.WriteLine($"{Thread.CurrentThread.Name}等待中");
_semaphoreSlim.Wait();
Console.WriteLine($"{Thread.CurrentThread.Name}上廁所");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{Thread.CurrentThread.Name}上完了!");
_semaphoreSlim.Release();
}
static void Main(string[] args)
{
// 假设廁所只有3個,但有5人要上廁所,所以有2位需要等待
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(() => {
Toilet(new Random().Next(2, 4));
});
t.Name = $"t{i}";
t.Start();
}
Console.ReadKey();
}
}
}
執行結果如下:
廁所有三間,一開始 t0, t1, t4先上廁所,等 t0上完廁所了,t2才進入上廁所狀態。
作用在不同Process之間,同一時間內只授予一個Thread在共享資源的獨佔訪問。就好像是馬桶一樣,一次只能有一個人用,下一個想用馬桶的人只能等待。Semaphore
限制在同一時間內,允許訪問共享資源的Thread數量上限。就像百貨公司的廁所一樣,假設共有10間,一次最多就只能10個人同時上廁所,其餘想上廁所的人就得排隊等待。
以下是 Mutex範例:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的Mutex機制
* ********************/
string mutexName = "互斥量";
using (var mutex = new Mutex(false, mutexName))
{
if (mutex.WaitOne(TimeSpan.FromSeconds(5), false))
{
Console.WriteLine("占用一下");
Console.ReadLine();
mutex.ReleaseMutex();
}
else
{
Console.WriteLine("我搶不到");
}
}
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
}
同時執行兩個Process時,第一個Process會看到占用一下,第二個Process會看到我搶不到,
以下是 Semaphore範例:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(3);
/// <summary>
/// 在上廁所
/// </summary>
/// <param name="seconds"></param>
static void Toilet(int seconds)
{
Console.WriteLine($"{Thread.CurrentThread.Name}等待中");
_semaphoreSlim.Wait();
Console.WriteLine($"{Thread.CurrentThread.Name}上廁所");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine($"{Thread.CurrentThread.Name}上完了!");
_semaphoreSlim.Release();
}
static void Main(string[] args)
{
// 假设廁所只有3個,但有5人要上廁所,所以有2位需要等待
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(() => {
Toilet(new Random().Next(2, 4));
});
t.Name = $"t{i}";
t.Start();
}
Console.ReadKey();
}
}
}
執行結果如下:
廁所有三間,一開始 t0, t1, t4先上廁所,等 t0上完廁所了,t2才進入上廁所狀態。
C# 執行緒(Thread)的Mointer探討
Mointer跟Lock一樣,具有「鎖」的功用,用來確保在critical section中只有一個執行緒能夠執行,使用Monitor.Enter()進入鎖定,Monitor.Exit() 退出鎖定,他其實就是Lock機制的應用:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
{ body }
}
finally
{
if (lockWasTaken) Monitor.Exit(temp);
}
另外他還提供了其他方法以供運用:
- Monitor.Enter() : Acquires an exclusive lock on the specified object. This action also marks the beginning of a critical section.
- Monitor.Exit() : Releases an exclusive lock on the specified object. This action also marks the end of a critical section protected by the locked object.
- Monitor.Pules() : Notifies a thread in the waiting queue of a change in the locked object's state.
- Monitor.Wait() : Releases the lock on an object and blocks the current thread until it reacquires the lock.
- Monitor.PulesAll() : Notifies all waiting threads of a change in the object's state.
- Monitor.TryEnter() : Attempts to acquire an exclusive lock on the specified object.
2019年3月1日 星期五
C# 執行緒(Thread)的Lock及Interlocked探討
同時啟動不同執行緒,但是對同一塊記憶體空間做內容的改變,可能會影響該內容的正確性(Race Condition),此時我們需要使用Lock來控制,當該執行緒執行時,其他執行緒無法使用這個被Lock的資源,以確保資料的正確性。另外C#也提供了一個Interlocked的方式,讓你能夠在Increment、Decrement、Add等基本數學操作不使用Lock的狀況下,保持結果正確,
以下測試的概念是對同一個記憶體空間做++和--,正確的結果應該為0,但若沒有Lock或Interlocked機制,不同執行緒會更改同一塊記憶體的值,譬如threadOne執行了++,尚未執行--,而threadTwo此時又執行++,這時候就會出現誤差,導致最終結果錯誤。
執行10次的結果,Counter每次都不一樣,但CounterWithLock及CounterNoLock則每次都為0。
以下為程式代碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的Lock機制
* ********************/
//沒有使用Lock
var c = new Counter();
var threadOne = new Thread(() => CountNumbers(c));
var threadTwo = new Thread(() => CountNumbers(c));
var threadThree = new Thread(() => CountNumbers(c));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c.Count}");
//使用Lock
var c1 = new CounterWithLock();
threadOne = new Thread(() => CountNumbers(c1));
threadTwo = new Thread(() => CountNumbers(c1));
threadThree = new Thread(() => CountNumbers(c1));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c1.Count}");
//使用Interlocked
var c2 = new CounterNoLock();
threadOne = new Thread(() => CountNumbers(c2));
threadTwo = new Thread(() => CountNumbers(c2));
threadThree = new Thread(() => CountNumbers(c2));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c2.Count}");
}
static void CountNumbers(CountBase cnt)
{
for (int i = 0; i <= 100000; i++)
{
cnt.Increase();
cnt.Descrease();
}
}
}
abstract class CountBase
{
public abstract void Increase();
public abstract void Descrease();
}
class Counter : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
_count++;
}
public override void Descrease()
{
_count--;
}
}
class CounterWithLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
private readonly object _SyncRoot = new Object();
public override void Increase()
{
//lock的對象必須是object(但不要lock string),不能是int, long等數值型
//若為public函數,不要lock(this),不然很容易造成deadlock
lock (_SyncRoot)
{
_count++;
}
}
public override void Descrease()
{
lock (_SyncRoot)
{
_count--;
}
}
}
class CounterNoLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
Interlocked.Increment(ref _count);
}
public override void Descrease()
{
Interlocked.Decrement(ref _count);
}
}
}
以下測試的概念是對同一個記憶體空間做++和--,正確的結果應該為0,但若沒有Lock或Interlocked機制,不同執行緒會更改同一塊記憶體的值,譬如threadOne執行了++,尚未執行--,而threadTwo此時又執行++,這時候就會出現誤差,導致最終結果錯誤。
執行10次的結果,Counter每次都不一樣,但CounterWithLock及CounterNoLock則每次都為0。
以下為程式代碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的Lock機制
* ********************/
//沒有使用Lock
var c = new Counter();
var threadOne = new Thread(() => CountNumbers(c));
var threadTwo = new Thread(() => CountNumbers(c));
var threadThree = new Thread(() => CountNumbers(c));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c.Count}");
//使用Lock
var c1 = new CounterWithLock();
threadOne = new Thread(() => CountNumbers(c1));
threadTwo = new Thread(() => CountNumbers(c1));
threadThree = new Thread(() => CountNumbers(c1));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c1.Count}");
//使用Interlocked
var c2 = new CounterNoLock();
threadOne = new Thread(() => CountNumbers(c2));
threadTwo = new Thread(() => CountNumbers(c2));
threadThree = new Thread(() => CountNumbers(c2));
threadOne.Start();
threadTwo.Start();
threadThree.Start();
threadOne.Join();
threadTwo.Join();
threadThree.Join();
Console.WriteLine($"Total is {c2.Count}");
}
static void CountNumbers(CountBase cnt)
{
for (int i = 0; i <= 100000; i++)
{
cnt.Increase();
cnt.Descrease();
}
}
}
abstract class CountBase
{
public abstract void Increase();
public abstract void Descrease();
}
class Counter : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
_count++;
}
public override void Descrease()
{
_count--;
}
}
class CounterWithLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
private readonly object _SyncRoot = new Object();
public override void Increase()
{
//lock的對象必須是object(但不要lock string),不能是int, long等數值型
//若為public函數,不要lock(this),不然很容易造成deadlock
lock (_SyncRoot)
{
_count++;
}
}
public override void Descrease()
{
lock (_SyncRoot)
{
_count--;
}
}
}
class CounterNoLock : CountBase
{
private int _count;
public int Count { get { return _count; } }
public override void Increase()
{
Interlocked.Increment(ref _count);
}
public override void Descrease()
{
Interlocked.Decrement(ref _count);
}
}
}
C# 執行緒(Thread)參數傳遞方式
在此介紹幾種執行緒中參數該如何傳遞:
以下為程式碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的傳遞參數
* ********************/
//方法一:使用建構子方式
var sample = new ThreadSample(3);
var threadOne = new Thread(sample.CountNumbers);
threadOne.Name = "One";
threadOne.Start();
threadOne.Join();
//方法二:利用Start接收object單個參數的方式傳遞參數,裡頭再去轉型
var threadTwo = new Thread(Count);
threadTwo.Name = "Two";
threadTwo.Start(4);
threadTwo.Join();
//方法三:利用lambda表達式
var threadThree = new Thread(() => CountNumbers(5));
threadThree.Name = "Three";
threadThree.Start();
threadThree.Join();
//觀察列印出來的值會發現都是20
int i = 10;
var threadFour = new Thread(() => PrintNumber(i));
i = 20;
var threadFive = new Thread(() => PrintNumber(i));
threadFour.Start();
threadFive.Start();
}
static void Count(object iterations)
{
CountNumbers((int)iterations);
}
static void PrintNumber(int number)
{
Console.WriteLine(number);
}
static void CountNumbers(int iterations)
{
for (int i = 0; i <= iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
class ThreadSample
{
private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for(int i=0;i<= _iterations;i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
}
- 利用建構子的方式,new class時把參數帶入
- 利用Start接收object單個參數的方式傳遞參數
- 利用lambda表達式調用方法
以下為執行結果
以下為程式碼:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
/** *******************
* Thread的傳遞參數
* ********************/
//方法一:使用建構子方式
var sample = new ThreadSample(3);
var threadOne = new Thread(sample.CountNumbers);
threadOne.Name = "One";
threadOne.Start();
threadOne.Join();
//方法二:利用Start接收object單個參數的方式傳遞參數,裡頭再去轉型
var threadTwo = new Thread(Count);
threadTwo.Name = "Two";
threadTwo.Start(4);
threadTwo.Join();
//方法三:利用lambda表達式
var threadThree = new Thread(() => CountNumbers(5));
threadThree.Name = "Three";
threadThree.Start();
threadThree.Join();
//觀察列印出來的值會發現都是20
int i = 10;
var threadFour = new Thread(() => PrintNumber(i));
i = 20;
var threadFive = new Thread(() => PrintNumber(i));
threadFour.Start();
threadFive.Start();
}
static void Count(object iterations)
{
CountNumbers((int)iterations);
}
static void PrintNumber(int number)
{
Console.WriteLine(number);
}
static void CountNumbers(int iterations)
{
for (int i = 0; i <= iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
class ThreadSample
{
private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for(int i=0;i<= _iterations;i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine($"{Thread.CurrentThread.Name} prints {i}");
}
}
}
}
訂閱:
文章 (Atom)