Ví dụ đa luồng trên hệ thống cụ thể

Một phần của tài liệu Giáo trình Hệ điều hành (Trang 48 - 52)

CHƯƠNG 2 : QUẢN LÝ TIẾN TRÌNH

2.2. LUỒNG

2.2.2. Ví dụ đa luồng trên hệ thống cụ thể

Để dễ hình dung về khái niệm đa luồng, trong phần này sẽ trình bầy ví dụ cụ thể về việc tạo ra luồng trong tiến trình khi lập trình đa luồng trên Java và lập trình đa luồng cho Windows sử dụng ngơn ngữ C++. Đây là các ví dụđơn giản để tiện cho việc theo dõi và hiểu khái niệm.

a. Đa lung trong Java

Ngôn ngữJava được xây dựng với nhiều cơ chế hỗ trợ lập trình đa luồng, bao gồm việc tạo ra, quản lý, đồng bộ hóa các luồng trong tiến trình. Máy ảo Java đóng vai trị ánh xạ các luồng do thư viện ngôn ngữ tạo ra thành các luồng mức nhân (xem khái niệm luồng mức nhân

ở phần sau) của hệđiều hành cụ thể, nhờ vậy các chương trình đa luồng viết trên Java có thể

chạy trên nhiều hệđiều hành như Windows, Linux, Mac OS, Android.

Dưới đây là ví dụ một chương trình đa luồng viết trên Java (chương trình được viết đơn

giản nhất với mục đích minh họa cách tạo ra luồng trong Java).

public class ThreadTest {

public static void main(String [] args) {

MyThread t1 = new MyThread(0, 300, 3); MyThread t2 = new MyThread(1, 300, 3); MyThread t3 = new MyThread(2, 300, 3); t1.start();

t2.start(); t3.start(); }

}

public class MyThread extends Thread {

private int first, last, step;

public MyThread(int s, int n, int m) { this.start = s; this.end = n; this.step = m; }

public void run() {

for(int i = this.first; i < this.last; i+=this.step) {

System.out.println("[ID " +this.getId() + "] " + i); Thread.yield();

} } }

Hình 2.5: Ví dụchương trình đa luồng đơn giản trên Java

Khi chạy, chương trình này in ra những dịng đầu tiên như sau (lưu ý: thứ tự in ra thực tế có thểthay đổi tùy thuộc vào lần chạy và máy tính cụ thể; ởđây chỉ gồm một phần kết quả được in ra): [ID 8] 0 [ID 9] 1 [ID 10] 2 [ID 8] 3 [ID 9] 4 [ID 8] 6 [ID 10] 5 [ID 9] 7 PTIT

Đoạn chương trình trên hoạt động như sau. Lớp MyThread kế thừa lớp Thread của Java,

trong đó quan trọng nhất là MyThread thay thếphương thức run() bằng phương thức run() của

mình. Đây là một trong hai cách tiêu chuẩn để tạo ra luồng trong Java. Phương thức run() là

điểm vào của luồng.

Trong phương thức main(), chương trình tạo ra ba luồng MyThread theo hai bước: bước 1 là tạo ra ba đối tượng MyThread bằng các lệnh new MyThread, bước là cho các luồng chạy bằng cách gọi phương thức start. Khi gọi start, luồng tương ứng sẽ thực hiện, bắt đầu từ phần mã chứa trong hàm run.

Mỗi luồng trong ba luồng vừa được tạo ra in ra các số trong khoảng từ first tới last với

bước nhẩy step cùng với số định danh của luồng được trả về bằng phương thức getID() của lớp Thread. Do ba luồng bắt đầu với giá trị first khác nhau nên luồng thứ nhất sẽ in các số 0,

3, 6, …, luồng thứ 2 in các số 1, 4, 7, …, và luồng thứba in ra 2, 5, 8, … Khi ba luồng chạy

đồng thời, kết quả in ra của ba luồng sẽ trộn vào nhau cho kết quả như trên. Phương thức

Thread.yield() được thêm vào để không luồng nào chạy trong thời gian quá lâu.

Bên cạnh cách tạo ra luồng bằng cách kế thừa class Thread và phủ quyết phương thức

run() như ở trên, một kỹ thuật thông dụng nữa để tạo ra luồng trong Java là tạo ra lớp để triển khai giao diện Runnable và phương thức run() của giao diện này. Giao diện Runnable được

định nghĩa như sau:

public interface Runnable {

public abstract void run(); }

b. Ví dđa lung trong Windows

Windows là hệ điều hành hỗ trợ đa luồng. Giao diện lập trình Windows API chứa các hàm cho phép tạo ra và xác định tham số quản lý luồng. Ngồi ra, Windows API cịn cung cấp các công cụđồng bộ luồng.

Dưới đây là ví dụ chương trình tạo ra nhiều luồng sử dụng hàm CreateThread do Windows API cung cấp. Chương trình này có nội dung tương tựchương trình ví dụđa luồng cho Java ở phần trên, trong đó tiến trình tạo ra ba luồng chạy đồng thời, mỗi luồng in ra các số trong khoảng từ start tới end. Chương trình được viết một cách đơn giản nhất đểngười đọc dễ theo dõi cách tạo ra luồng, và do vậy thiếu các phần về xử lý lỗi cũng như các chức năng

nâng cao liên quan tới quản lý luồng trong Windows.

#include <windows.h> #include <stdio.h> struct thread_data { int id; int start; int end; int step;

thread_data(int _id, int _start, int _end, int _step) :

id(_id), start(_start), end(_end), step(_step) {} };

DWORD WINAPI thread_func(LPVOID lpParameter) {

thread_data *td = (thread_data*)lpParameter;

for (int i = td->start; i < td->end; i+= td->step){ printf("\n[id = %d]: %d", td->id, i);

Sleep(1); }

return 0; }

void main(int argc, char ** argv) { CreateThread(NULL, 0, thread_func, new thread_data(0,0,300,3),0,0); CreateThread(NULL, 0, thread_func, new thread_data(1,1,300,3),0,0); CreateThread(NULL, 0, thread_func, new thread_data(2,2,300,3),0,0); getchar(); }

Hình 2.6. Ví dụchương trình đa luồng đơn giản trên Windows

Khi chạy, một phần kết quả được in ra có dạng như bên dưới (thứ tự in ra có thể thay

đổi tùy vào lần chạy và hệ thống cụ thể; kết quảđầy đủ phải gồm các số nhỏhơn 300).

[id = 0]: 0 [id = 2]: 2 [id = 1]: 1 [id = 0]: 3 [id = 1]: 4 [id = 2]: 5 [id = 1]: 7 [id = 0]: 6 [id = 2]: 8 [id = 0]: 9 [id = 1]: 10

Chương trình làm việc như sau. Từ hàm main(), tiến trình chính gọi hàm CreateThread ba lần để sinh ra ba luồng. Trong các tham số của hàm CreateThread có con trỏ tới hàm

thread_func, là điểm bắt đầu của luồng tương ứng. Người lập trình có thểthay đổi hàm này để

chạy các luồng khác nhau theo ý muốn. Một tham số khác của CreateThread chứa con trỏ tới tham số cần truyền cho luồng, ởđây là con trỏ tới cấu trúc dữ liệu thread_data. Việc sử dụng cấu trúc này là cần thiết vì ởđây cần truyền cho mỗi luồng bốn tham số. Cấu trúc thread_data

được khai báo với ba tham số start, end, step là bắt đầu, kết thúc, và bước nhẩy cho vòng lặp, ngồi ra cịn chứa thêm sốđịnh danh id để dễ phân biệt kết quả của mỗi luồng. Mỗi luồng khi chạy sẽ in ra id của mình cùng với các số trong khoảng start – end với cùng bước nhẩy là 3.

Lưu ý, trong chương trình trên, hàm Sleep() được thêm vào để các luồng có khoảng dừng nhỏ, nhờ vậy các luồng khác có thể chạy xen kẽ. Hàm Sleep() ởđây đóng vai trị tương

tự Thread.yield() trong ví dụ với Java. Ngồi ra, thơng thường luồng chính bắt đầu từ hàm main() phải chờ cho tới khi các luồng con kết thúc. Để cho đơn giản, ở đây sử dụng hàm getchar(). Người dùng sẽđợi tới khi các luồng con in xong kết quả và kết thúc mới bấm phím

để kết thúc luồng chính.

Một phần của tài liệu Giáo trình Hệ điều hành (Trang 48 - 52)

Tải bản đầy đủ (PDF)

(184 trang)