banner
 .::Others::. Lập trình an toàn với Ada - 8 Go to original post Author: NQL05 - Translator:  - Entry Date: 13/02/2009 11:07:54
Phần 2 của loạt bài tiếp cận lập trình đa luồng (multi-thread) và cái nhìn dưới con mắt Ada.


Mỗi con sông đều có nhiều luồng nước chảy

Các ứng dụng đa luồng thống trị thế giới phần mềm. Mỗi ứng dụng tương tác, bất kể trên desktop hay server đều cần hoạt động theo nhiều luồng để cho “cục cưng” người dùng có cảm giác mọi ý muốn của hắn đều được thỏa mãn ngay tức thì và máy tính chỉ hầu hạ cho riêng hắn. Qua phần này, không những bạn sẽ được biết về luồng nói chung, mà còn được biết các luồng hoạt động như thế nào trong Ada. Ada hỗ trợ lập trình đa luồng bằng những kết cấu đặc biệt của ngôn ngữ. Nói vắn tắt, một thứ gì đó khác hẳn luồng trong Linux, Win32, Java và .NET.

Một chút thuật ngữ
Thuật ngữ, như ta vẫn thường thấy, là một mớ bòng bong. Cùng một sự vật, các hệ thống *NIX đặt tên một đàng, Microsoft đặt tên một nẻo; thuật ngữ trong tài liệu người dùng khác xa với tài liệu lập trình viên; mỗi ngôn ngữ lập trình tự đặt ra các thuật ngữ của riêng mình. Rồi dịch thuật không thống nhất cũng làm cho vấn đề rối ren thêm nữa. Trong bài này, người viết sẽ dùng khái niệm quá trình (process) để chỉ đối tượng của hệ điều hành, chứa một hay nhiều luồng (thread). Tất cả các luồng của một quá trình dùng chung một không gian địa chỉ, nhưng mỗi luồng đều có ngăn xếp (stack) của riêng mình. Ngôn ngữ Ada đặt ra thuật ngữ tác vụ (task) mà về bản chất, đó chính là luồng.

Cơ hội?...
Hãy tưởng tượng bạn dùng một chương trình e-mail client. Sau khi bạn viết xong một lá thư và ấn nút Send, chương trình phải thực hiện một hành động nào đó. Nó phải kết nối với một e-mail server nào đó rồi chuyển lá thư đi. Việc này có thể kéo dài hàng chục giây. Nếu giả thử mọi hành động đều diễn ra trong một luồng thì chương trình client của bạn trong suốt khoảng thời gian đó sẽ “treo” cứng. Điều đó chẳng thể làm cho bạn vui lòng, bạn muốn viết một lá thư khác nữa kia mà. Đa luồng sẽ giải quyết tình huống này một cách đẹp mắt. Sau khi ấn nút Send chương trình client tạo ra một luồng mới có nhiệm vụ gửi thư. Việc tạo luồng diễn ra rất nhanh, trong nháy mắt bạn có thể bắt tay vào lá thư mới. Việc phát sinh một luồng mới nào đó chạy mất hàng chục giây để gửi thư, bạn chả bận tâm.

... Và thách đố?
Khi chạy một quá trình, hệ điều hành khởi động một luồng duy nhất. Tạo thêm những luồng mới là công việc của người lập trình. Thường là bằng cách gọi một hàm nào đó có trong thư viện của ngôn ngữ và liên hệ trực tiếp với một thủ tục (routine) tương ứng nào đó của hệ điều hành. Một hàm như thế thường tiếp nhận địa chỉ của một phân trình, lấy địa chỉ ấy làm điểm xuất phát cho luồng mới.

Rồi cần phải có các công cụ để điều khiển các luồng đã tạo. Các luồng cần trao đổi thông tin với nhau, ta thường phải đảm bảo rằng hai luồng không làm việc đồng thời trên một biến toàn cục, vân vân. Phục vụ cho việc đó là "kính thưa" các kiểu đối tượng nguyên sơ (primitive) như đoạn găng (critical section), khóa (lock), cờ hiệu (semaphore), mutex (13), mutant (14). Chúng ta sẽ không quan tâm tìm hiểu ý nghĩa của những từ này; điều quan trọng là để làm việc với những đối tượng này, có các thủ tục trong kernel hệ điều hành và, tương ứng với chúng, có các hàm trong các ngôn ngữ lập trình.

Nếu lập trình ở mức thấp nhất, người lập trình thường gọi thẳng các thủ tục của hệ điều hành. Thí dụ để tạo luồng mới Linux có pthread_create, Win32 có CreateThread. Lập trình như thế, mã nguồn sẽ không thể chuyển đặt (portable). Khó khăn này có thể xử lý bằng một thư viện che phủ tầng thấp nhất đó, nhưng chúng ta, lập trình viên lười biếng, muốn có nhiều tiện nghi hơn. Trong Java (và do đó cả trong C#) tình thế vẫn tương tự, thư viện chuẩn cung cấp một lớp nào đó nối thẳng vào tận ruột gan của Máy Ảo (Virtual Machine) và cho phép chạy một phương thức (method) trong một luồng mới. Java còn hỗ trợ đa luồng bằng cả những kết cấu làm đồng bộ luồng.

Đối tượng nguyên sơ, thủ tục kernel, thư viện hay kết cấu ngôn ngữ nói trên đều là những công cụ hỗ trợ mức thấp. Lập trình đa luồng với chúng là một công việc căng thẳng, đầy mệt mỏi và dễ gây sai sót, có thể ví như như lập trình bằng hợp ngữ vậy.

Quên đi tất cả, đến với Ada
Chính thế. Với Ada mọi chuyện đều khác. Luồng trong Ada được nhìn từ một tầm trừu tượng hóa cao hơn, chứa đựng một quan điểm toàn diện hơn nhiều. Luồng Ada, hay còn gọi là tác vụ, là một thực thể đặc biệt. Không những có thể khai báo một tác vụ đơn lẻ mà còn có thể khai báo kiểu tác vụ, một thứ khuôn mẫu để từ đó tạo ra nhiều tác vụ giống nhau. Ta hãy bắt đầu với một Hello World đa luồng.
Code:


with Ada.Text_IO;

use Ada.Text_IO;

procedure Hello_Example is

task type Hello_Task is -- đặc tả tác vụ
-- giao diện (rỗng)
end Hello_Task;

task body Hello_Task is -- thân tác vụ
begin
Put_Line("Hello from thread");
end Hello_Task;

H1, H2, H3 : Hello_Task; -- 3 tác vụ (3 luồng) giống nhau
-- song song với luồng chính
begin -- Tại đây, cả 4 luồng cùng khởi động
Put_Line("Hello from main thread");
end Hello_Example;



Đây là một chương trình đầy đủ, chạy được. Ở đầu ta xác lập một kiểu Hello_Task, thể hiện một luồng nào đó làm khuôn mẫu. Định nghĩa của kiểu này được chia thành hai phần rời hẳn nhau: đặc tả (specification) và thân (body). Đặc tả ở đây rất đơn giản, thực chất chỉ có mỗi cái tên. Thân cũng rất đơn giản, chỉ viết ra câu “Hello from thread” rồi kết thúc. Kế đó ta khai báo ba biến (H1, H2 và H3) của kiểu Hello_Task, cũng y hệt như mọi biến khác mà thôi. Câu khai báo này cho biết ta cần ba tác vụ kiểu Hello_Task và hệ thống sẽ khởi động chúng khi bắt đầu vào đến thân chương trình, tức là điểm begin kế đó. Khi luồng chính bắt đầu viết ra câu “Hello from main thread” thì đã có cả thảy bốn luồng cùng chạy song song. Trên màn hình sẽ hiển thị bốn dòng sau đây, theo một thứ tự ngẫu nhiên nào đó.

Code:


Hello from thread

Hello from thread
Hello from main thread
Hello from thread





______________________________
NOTES

(13) Sinh từ mutual exclusion (loại trừ lẫn nhau).

(14) Đây là đặc sản trong thực đơn tiếng lóng của Microsoft, dùng để chỉ một dị bản của mutex cho Windows NT kernel, chứ không phải là “quái nhân đột biến gene” smilie.
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Other posts in the same group:

Lập trình an toàn với Ada - 8
Go to top Go to original post  

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|