Tiến trình và tiểu trình
Bạn không nên nhầm lẫn giữa process (tiến trình) và thread (tiểu trình). Process có thể hiểu là một instance của chương trình máy tính được thực thi, dựa trên hệ điều hành, hoàn toàn độc lập với các tiến trình khác. Còn thread là một nhóm lệnh được tạo ra để thực thi một tác vụ trong một process, chúng chia sẻ chung dữ liệu với nhau để xử lý, điều này là cần thiết nhưng cũng là nguyên nhân dễ gây ra lỗi nếu bạn không xử lý đúng cách.
Thread hay còn gọi là tiểu trình là khái niệm khá quen thuộc trong lập trình. Thread cho phép chương trình thực hiện đồng thời nhiều tác vụ, và giúp quá trình tương tác với người dùng không bị gián đoạn, lập trình song song và là kĩ thuật không thể thiếu trong các ứng dụng về mạng. Trong bài này, bạn sẽ được giới thiệu cơ bản về cách làm việc với thread cũng như kĩ thuật đồng bộ hóa và hiện tượng deadlock.
.Net cung cấp lớp Thread trong namespace System.Threading cùng với những phương thức cần thiết để giúp lập trình viên sử dụng một cách đơn giản và hiệu quả. Để tạo một thread mới bạn làm theo các bước sau:
– Tạo đối tượng Thread và truyền một delegate ThreadStart chứa phương thức sẽ thực thi vào constructor của Thread.
– Chạy thread: Gọi phương thức Start() của đối tượng thread vừa tạo.
using System;
using System.Threading;
namespace TLSDataSlot
{
class Program
{
static void Main()
{
Thread[] newThreads = new Thread[4];
for (int i = 0; i < newThreads.Length; i++)
{
newThreads[i] =
new Thread(new ThreadStart(Slot.SlotTest));
newThreads[i].Start();
}
}
}
class Slot
{
static Random randomGenerator = new Random();
public static void SlotTest()
{
// Set different data in each thread's data slot.
Thread.SetData(
Thread.GetNamedDataSlot("Random"),
randomGenerator.Next(1, 200));
// Write the data from each thread's data slot.
Console.WriteLine("Data in thread_{0}'s data slot: {1,3}",
AppDomain.GetCurrentThreadId().ToString(),
Thread.GetData(
Thread.GetNamedDataSlot("Random")).ToString());
// Allow other threads time to execute SetData to show
// that a thread's data slot is unique to the thread.
Thread.Sleep(1000);
Console.WriteLine("Data in thread_{0}'s data slot is still: {1,3}",
AppDomain.GetCurrentThreadId().ToString(),
Thread.GetData(
Thread.GetNamedDataSlot("Random")).ToString());
// Allow time for other threads to show their data,
// then demonstrate that any code a thread executes
// has access to the thread's named data slot.
Thread.Sleep(1000);
Other o = new Other();
o.ShowSlotData();
Console.ReadLine();
}
}
public class Other
{
public void ShowSlotData()
{
// This method has no access to the data in the Slot
// class, but when executed by a thread it can obtain
// the thread's data from a named slot.
Console.WriteLine(
"Other code displays data in thread_{0}'s data slot: {1,3}",
AppDomain.GetCurrentThreadId().ToString(),
Thread.GetData(
Thread.GetNamedDataSlot("Random")).ToString());
}
}
}
using System;
using System.Threading;
namespace ThreadStatic
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
Thread newThread = new Thread(ThreadData.ThreadStaticDemo);
newThread.Start();
}
}
}
class ThreadData
{
[ThreadStaticAttribute]
static int threadSpecificData;
public static void ThreadStaticDemo()
{
// Store the managed thread id for each thread in the static
// variable.
threadSpecificData = Thread.CurrentThread.ManagedThreadId;
// Allow other threads time to execute the same code, to show
// that the static data is unique to each thread.
Thread.Sleep(1000);
// Display the static data.
Console.WriteLine("Data for managed thread {0}: {1}",
Thread.CurrentThread.ManagedThreadId, threadSpecificData);
}
}
}
Truyền tham số cho thread
Thread(ThreadStart)
Thread(ParameterizedThreadStart)
No Parameters
Hide Copy Code
Thread workerThread = new Thread(StartThread);
Console.WriteLine("Main Thread Id {0}",
Thread.CurrentThread.ManagedThreadId.ToString());
workerThread.Start();
....
....
public static void StartThread()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Thread value {0} running on Thread Id {1}",
i.ToString(),
Thread.CurrentThread.ManagedThreadId.ToString());
}
}
Single Parameter
Hide Copy Code
//using parameter
Thread workerThread2 = new Thread(ParameterizedStartThread);
// the answer to life the universe and everything, 42 obviously
workerThread2.Start(42);
Console.ReadLine();
....
....
public static void ParameterizedStartThread(object value)
{
Console.WriteLine("Thread passed value {0} running on Thread Id {1}",
value.ToString(),
Thread.CurrentThread.ManagedThreadId.ToString());
}
CallBack
using System;
using System.Threading;
namespace CallBacks
{
class Program
{
private string message;
private static Timer timer;
private static bool complete;
static void Main(string[] args)
{
Program p = new Program();
Thread workerThread = new Thread(p.DoSomeWork);
workerThread.Start();
//create timer with callback
TimerCallback timerCallBack =
new TimerCallback(p.GetState);
timer = new Timer(timerCallBack, null,
TimeSpan.Zero, TimeSpan.FromSeconds(2));
//wait for worker to complete
do
{
//simply wait, do nothing
} while (!complete);
Console.WriteLine("exiting main thread");
Console.ReadLine();
}
public void GetState(Object state)
{
//not done so return
if (message == string.Empty) return;
Console.WriteLine("Worker is {0}", message);
//is other thread completed yet, if so signal main
//thread to stop waiting
if (message == "Completed")
{
timer.Dispose();
complete = true;
}
}
public void DoSomeWork()
{
message = "processing";
//simulate doing some work
Thread.Sleep(3000);
message = "Completed";
}
}
}