Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 42 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
42
Dung lượng
237,2 KB
Nội dung
Lập trình Windows Multithread Parallel programming NET Mục tiêu cần nắm Generic Types, Methods Delegates Anonymous method Lambda Expression Multithread programming Generic Types Generic nghĩa “tổng quát” hàm ý đưa cách làm chung cho nhiều vấn đề Tình ví dụ cần xây dựng Ngăn xếp (Stack) chứa kiểu liệu int với phương thức như: push, pop, kiểm tra,… Sau lại cần xây dựng Stack với phương thức liệu lại string Giải pháp cho vấn đề trên? public class IntStack { int[] _data = new int[100]; int _curIdx = -1; public void Push(int value) { _data[++_curIdx] = value; } public int Pop() { return _data[_curIdx ]; } } Cách thường làm: copy lại thay đổi kiểu liệu code Sẽ tiếp tục có yêu cầu đổi kiểu liệu sang kiểu liệu khác float, double,… Cách tốt biết đến kiểu liệu sở NET object Khi sử dụng kiểu liệu object Stack chấp nhận kiểu liệu? public class ObjectStack { object[] _data = new object[100]; int _curIdx = -1; public void Push(object value) { _data[++_curIdx] = value; } public object Pop() { return _data[_curIdx ]; } } Vấn đề ObjectStack kể dễ gây lỗi runtime (tức giải tốt mặt syntax) ObjectStack s = new ObjectStack(); //push vào kiểu string s.Push("test"); //lấy lại kiểu int int i = (int)s.Pop(); NET cung cấp giải pháp cho vấn đề thông qua khái niệm Generic Generic tính NET Framework 2.0 và tích hợp sâu Common Language Runtime (CLR) Trong NET Framework, Generic giới thiệu khái niệm kiểu tham số dùng để thiết kế class phương thức nhằm để trì hoãn kiểu liệu lớp phương thức khai báo khởi tạo Một điểm bật kiểu Generic cho phép kiểm tra cú pháp lúc biên dịch Có thể sử dụng nhiều kiểu liệu khác với đoạn code (tương tự khái niệm Template C++) Bằng cách sử dụng tham số T tham số chung, ta tạo class mà tham chiếu tới không gặp lỗi xảy lúc runtime ép kiểu boxing (chuyển giá trị từ value type sang reference type) public class GenericStack { T[] _data = new T[100]; int _curIdx = -1; public void Push(T value) { _data[++_curIdx] = value; } public T Pop() { return _data[_curIdx ]; } } // sử dụng GenericStack s = new GenericStack(); Generic Methods Là hàm thông dụng (cách hành xử chung cho kiểu liệu) nên cài đặt theo kiểu Generic (sử dụng tham số đầu vào hay đầu generic) static void Swap(ref T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; } Generic Delegates Tương tự với method, delegate cài đặt theo kiểu generic (nhằm làm tham số hàm chung cho số trường hợp) public delegate void MyDelegate(T param); Trong NET khai báo sẵn số generic delegate như: Predicate, Action, Comparison,… Predicate sử dụng để kiểm tra giá trị có thỏa mãn điều kiện không trả kiểu bool Action sử dụng để thực hành động với đối tượng mà ta truyền vào không trả giá trị Comparison dùng để so sánh hai đối tượng kiểu, thường sử dụng trường hợp xếp … Ví dụ thường gặp phương thức tĩnh cung cấp class Array Ví dụ static void Main(string[] args) { Thread t1 = new Thread(new ParameterizedThreadStart(Method)); Thread t2 = new Thread(new ParameterizedThreadStart(Method)); t1.Start("A"); t2.Start("B"); } static void Method(object param) { string str = (string)param; for (int i = 0; i < 100; ++i) Console.Write(str); } Sử dụng lambda expression static void Main(string[] args) { Thread t1 = new Thread((param) => { string str = (string)param; for (int i = 0; i < 100; ++i) Console.Write(str); }); Thread t2 = new Thread((param) => { string str = (string)param; for (int i = 0; i < 100; ++i) Console.Write(str); }); t1.Start("A"); t2.Start("B"); } Property quan trọng Thread ThreadState cho thấy trạng thái thread Mỗi lời gọi phương thức thread làm thay đổi giá trị thuộc tính Unstarted, Running, Suspended, Stopped, Aborted,… ThreadPriority xác định mức độ ưu tiên mà thread thực thi so với thread khác Mỗi thread tạo mang giá trị priority Normal Các giá trị mà thuộc tính có bao gồm: Lowest, BelowNormal, Normal, AboveNormal Highest Các phương thức thông dụng Thread Abort(): phương thức gọi, hệ thống ném ngoại lệ ThreadAbortException để kết thúc thread Sau gọi phương thức này, thuộc tính ThreadState chuyển sang giá trị Stopped Suspend(): phương thức tạm dừng việc thực thi Thread vô thời hạn yêu cầu chạy tiếp tục với phương thức Resume() Tuy nhiên hai phương thức gắn attribute Obsolete để khuyến cáo ta nên sử dụng phương pháp khác để thay Sleep(): để dừng thread khoảng thời gian tính milisecond, thread chuyển sang trạng thái WaitSleepJoin Chú ý phương thức static không cần tạo đối tượng Thread gọi nó, ví dụ: Thread.Sleep(1000) Tùy vào ngữ cảnh gọi Thread.Sleep(), mà Thread thực thi dòng lệnh bị ảnh hưởng Join(): phương thức hữu ích trường hợp cần thực tác vụ sau thread kết thúc Phương thức dùng sau chạy Thread Các tác vụ nằm phía lệnh gọi Join() Thread thực thi sau Thread hoàn tất công việc Ví dụ static void Main(string[] args) { Thread t1 = new Thread(new ParameterizedThreadStart(Method)); Thread t2 = new Thread(new ParameterizedThreadStart(Method)); Thread t3 = new Thread(new ParameterizedThreadStart(Method)); t1.Start(new object[] { "A", }); t2.Start(new object[] { "B", 100 }); t2.Join(); t3.Start(new object[] { "C", }); } static void Method(object param) { object[] arrObj = (object[])param; string str = (string)arrObj[0]; int n = (int)arrObj[1]; Thread.Sleep(n); for (int i = 0; i < 100; ++i) Console.Write(str); } Kết C xuất sau B dù có làm chậm Thread Foreground Background Thread Foreground Thread Thread thực thi kết thúc chương trình (Thread chính) hoàn thành (hoặc bị bắt buộc ngừng) kết thúc Background Thread bị khai tử chương trình kết thúc Mặc định Thread tạo Foreground Thuộc tính để set Foreground hay Background IsBackground Ví dụ static void Main(string[] args) { Thread t1 = new Thread(() => { Thread.Sleep(1000); Console.WriteLine("Thread running "); }); Thread t2 = new Thread(() => { Thread.Sleep(1200); Console.WriteLine("Thread running "); }); t1.Start(); t2.IsBackground = true; t2.Start(); Console.WriteLine("Main ended "); } Thread Pooling Thread Pooling kĩ thuật cho phép sử dụng thread hiệu cách quản lý phân phối chúng hợp lý, tận dụng tối đa thời gian nhàn rỗi tăng hiệu suất chương trình Thread Pooling kĩ thuật áp dụng phổ biến ứng dụng I/O bất đồng tập tin truyền tải liệu mạng Một đặc điểm Thread pool thread đặt chế độ background (Background Thread) Để sử dụng thread pool đơn giản sử dụng phương thức tĩnh QueueUserWorkItem() lớp ThreadPool Ví dụ static void Main(string[] args) { ThreadPool.QueueUserWorkItem(funcWait, "A"); ThreadPool.QueueUserWorkItem(funcWait, "B"); Thread.Sleep(6000); } static void funcWait(object param) { string str = (string) param; for (int i = 0; i < 10; ++i) { Console.WriteLine("{0} running ", str); Thread.Sleep(500); } } Các vấn đề đụng độ Vấn đề nảy sinh Thread truy cập đến đối tượng, trạng thái chia sẻ bất đồng Ví dụ chương trình sau static int n = 0; static void Main(string[] args) { Thread t1 = new Thread(() => { for (int i = 0; i < 100; ++i){ n++; if (n > 0){ Thread.Sleep(2); Console.Write("{0}\t", n); } } }); Thread t2 = new Thread(() => { for (int i = 0; i < 100; ++i){ Thread.Sleep(1); n ; } }); t1.Start(); t2.Start(); } Giải vấn đề đồng Net cung cấp số kĩ thuật để đồng việc truy xuất liệu Một sử dụng, liệu bị khóa lại thread khác muốn sử dụng phải chờ liệu hay tài nguyên giải phóng Cụ thể phương pháp cung cấp là: Monitor, SpinLock, Mutex (Mutual exclusive), Semaphore, WaitHandle, Đơn giản sử dụng Lock Ví dụ static int n = 0; static object syncObj = new object(); static void Main(string[] args) { Thread t1 = new Thread(() => { for (int i = 0; i < 100; ++i){ lock (syncObj){ n++; if (n > 0){ Thread.Sleep(2); Console.Write("{0}\t", n); } } } }); Thread t2 = new Thread(() => { for (int i = 0; i < 100; ++i){ lock (syncObj){ Thread.Sleep(1); n ; } } }); t1.Start(); t2.Start(); } Deadlock Đồng hóa sử dụng thread công việc cần thiết, nhiên không cẩn thận gặp phải tình trạng chương trình dừng hoạt động vô thời hạn Tình trạng đặt tên Deadlock Deadlock xảy có hai thread đợi thread giải phóng, thật “trùng hợp” hai lại giữ “chìa khóa” Ví dụ static int m = 0, n = 0; static object syncM = new object(); static object syncN = new object(); static void Main(string[] args) { Thread t1 = new Thread(() => { lock (syncM){ m++; Thread.Sleep(100); Console.WriteLine("t1 holding m"); lock(syncN){ n ; Console.WriteLine("t1 holding n"); } } }); Thread t2 = new Thread(() => { lock (syncN) { n++; Thread.Sleep(100); Console.WriteLine("t2 holding n"); lock (syncM) { m ; Console.WriteLine("t2 holding m"); } } }); t1.Start(); t2.Start(); } [...]... 43).ToString()); Multithread Máy tính ngày nay thực hiện được đa nhiệm, đa tác vụ đồng thời dựa vào khái niệm Process và Thread Process (tiến trình) có thể hiểu là một thể hiện (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 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... đúng cách Ngữ cảnh sử dụng Tương tác với giao diện trong khi các tác vụ ngầm vẫn chạy Lướt web trong khi Chrome đồng bộ bookmark Thiết lập độ ưu tiên Hoạt động tiêu tốn nhiều thời gian không dừng toàn bộ ứng dụng Copy file dung lượng lớn! Import file vào CSDL … Namespace System.Threading Cung cấp lớp và giao diện cho lập trình đa luồng Class chính: Thread CurrentThread IsAlive... parameters) => expression Dấu mở và đóng ngoặc là tùy chọn trong trong trường hợp chỉ có 1 tham số, ngược lại nó là bắt buộc Nếu có nhiều hơn 1 tham số thì chúng sẽ được phân cách bằng dấu phẩy (,) Kiểu dữ liệu của các tham số có thể được khai báo tường minh hoặc không Nếu không khai báo, trình biên dịch sẽ tự xác định kiểu, tuy nhiên trong một số trường hợp, cần phải chỉ rõ kiểu dữ liệu //sẽ báo... Thread Pooling Thread Pooling là một kĩ thuật cho phép sử dụng các thread hiệu quả hơn bằng cách quản lý và phân phối chúng hợp lý, tận dụng tối đa thời gian nhàn rỗi và tăng hiệu suất của chương trình Thread Pooling là một kĩ thuật được áp dụng phổ biến trong các ứng dụng về I/O bất đồng bộ tập tin và truyền tải dữ liệu trên mạng Một đặc điểm của Thread pool là các thread sẽ được đặt ở chế độ background... một delegate với cách viết inline Cụ thể delegate void DelTest(int value); void funcTest() { DelTest dt = delegate(int value) { // }; } Áp dụng trong event Load += delegate(object sender, EventArgs e) { MessageBox.Show("Load raised "); }; Áp dụng trong các Generic Delegate StringBuilder sb = new StringBuilder(); void funcTest() { int[] arrInt = new int[] { 3, 5, 7, 2, 10, 43, 12, 34 }; //sử dụng... lỗi s => s.Length; //cần khai báo kiểu dữ liệu (string s) => s.Length; Trong lambda expression sử dụng toán tử =>, mang ý nghĩa như là “đi đến” Phía bên trái của toán tử là các tham số (nếu có), bên phải là các biểu thức hay câu lệnh Ví dụ: //lambda expression x => x * x; //hàm tương đương int f(int x) { return x * x; } Sử dụng trong Generic Delegate StringBuilder sb = new StringBuilder(); void... Console.Write("B"); }); t1.Start(); t2.Start(); } Truyền tham số cho Thread ParameteriedThreadStart là một giải pháp thay thế cho ThreadStart trong trường hợp cần truyền tham số cho thread Đối tượng delegate ParameteriedThreadStart này chỉ chấp nhận một tham số kiểu object, vì thế trong phương thức callback cần phải ép kiểu để sử dụng được đúng kiểu dữ liệu của tham số Ví dụ static void Main(string[] args)... Sleep(): để dừng thread hiện tại trong một khoảng thời gian tính bằng milisecond, khi đó thread sẽ chuyển sang trạng thái WaitSleepJoin Chú ý rằng đây là một phương thức static do đó không cần tạo đối tượng Thread khi gọi nó, ví dụ: Thread.Sleep(1000) Tùy vào ngữ cảnh gọi Thread.Sleep(), mà Thread thực thi dòng lệnh này sẽ bị ảnh hưởng Join(): đây là một phương thức hữu ích trong trường hợp cần thực hiện... làm chậm Thread 2 đi Foreground và Background Thread Foreground Thread là những Thread sẽ được thực thi cho đến khi kết thúc mặc dù chương trình (Thread chính) đã hoàn thành (hoặc bị bắt buộc ngừng) và kết thúc Background Thread thì sẽ bị khai tử ngay khi chương trình kết thúc Mặc định các Thread khi tạo ra là Foreground Thuộc tính để set Foreground hay Background là IsBackground Ví dụ static... pháp để sử dụng Func là viết các kiểu của tham số và giá trị trả về vào cặp ngoặc ‘’, theo sau từ khóa Func Func Trong đó T là các kiểu của tham số cần truyền vào và TResult là kiểu của giá trị trả về Lưu ý là Func yêu cầu ít nhất một tham số trong cặp ‘’, tức là phải có kiểu trả về Không để đặt void hay để một cặp ngoặc ‘’ rỗng khi dùng Func Ví dụ //ví dụ hàm tìm max 2 ...Mục tiêu cần nắm Generic Types, Methods Delegates Anonymous method Lambda Expression Multithread programming Generic Types Generic nghĩa “tổng quát” hàm ý đưa cách làm chung cho... int> findMax = (x, y) =>{ return (x > y) ? x : y; }; MessageBox.Show(findMax(27, 43).ToString()); Multithread Máy tính ngày thực đa nhiệm, đa tác vụ đồng thời dựa vào khái niệm Process Thread