BÁO CÁO THỰC HÀNH MÔN HỌC : HỆ ĐIỀU HÀNH Tp Hồ Chí Minh ,tháng 12 năm 2009 Tác giả : Trần Thế Toàn . 1. Nội dung bài tập thực hành : Bài a6 : Viết chương trình giao tiếp giữa hai tiến trình bằng cách sử dụng shared memory .Tiến trình A gửi 1 thông điệp(message ) sang tiến trình B và đợi tiến trình B phản hồi .Tiến trình B đợi thông điệp từ tiến trình A , sau đó phản hồi thông điệp cho tiến trình A . 2. Hướng giải quyết cho bài tập : Ta dùng cơ chế shared-memory thông qua memory mapped files . Hai tiến trình tham gia vàp quá trình giao tiếp là Proccess P0 và Process P1. Trong đó , đầu tiên P0 sẽ tạo ra File-mapping object , và chia sẻ file-mapping object này cho P1 thông qua tên của File-mapping object .P0 liên kết với File-mapping Object này trên cơ sở tạo ra một view trên vùng nhớ được liên kết tới , nhờ P0 tạo 1 view riêng cho mình rồi map tới file được chia sẻ . P1 không tạo File-mapping Object nữa , nó sử dụng File-mapping object do P0 tạo ra , P1 mở file mapping object và tạo 1 view riêng của nó , map vùng nhớ của tiến trình tới vùng dữ liệu chia sẻ giữa P0 và P1 . Sau khi việc chia sẻ vùng nhớ chung đã hoàn thành , ta tiến hành việc thực hiện giao tiếp giữa hai tiến trình ( hay có thể gọi là “chat” ).Tiến trình P0 sau khi tạo ra vùng dữ liệu chia sẻ , P1 sẽ mở 1 view lên vùng dữ liệu chia sẻ này , và sẽ là tiến trình giao tiếp trước . Sau khi P1 gửi thông điệp tới P0 , P1 sẽ không còn khả năng gửi tiếp thông điệp nữa mà nó phải chờ P0 hồi đáp lại 1 thông điệp . Việc giao tiếp giữa 2 tiến trình sẽ kết thúc nếu có bất kì bên nào nhập vào từ khóa “exit” , sau đó ấn Enter . 3. Cài đặt bài toán trên ngôn ngữ lập trình C : a. Tiến trình P0 : Bước 1 : Tạo File-mapping Object . hMapFile có kiểu HANDLE là giá trị trả về của hàm CreateFileMapping(…). HANDLE WINAPI CreateFileMapping( __in HANDLE hFile, __in LPSECURITY_ATTRIBUTES lpAttributes, __in DWORD flProtect, __in DWORD dwMaximumSizeHigh, __in DWORD dwMaximumSizeLow, __in LPCTSTR lpName ); Trong đó , tham số thứ nhất là HANLDE hFile , do yêu cầu của chương trình không yêu cầu lưu lại chat-log , để đơn giản cho chương trình , ta đưa vào giá trị INVALID_HANDLE_VALUE , nghĩa là thay vì tạo ra một file-mapping Object lên 1 file trên Disk , ta sẽ tạo một file-mapping Object lên Paging-File trong bộ nhớ . Với dòng lệnh trên ta tạo ra một File Mapping Object được xác định bởi MapObjName , được chia sẻ với thuộc tính PAGE_READWRITE. Bước 2 : Sau đó , ta tạo 1 view của P0 tới file – mapping . LPVOID WINAPI MapViewOfFile( __in HANDLE hFileMappingObject, __in DWORD dwDesiredAccess, __in DWORD dwFileOffsetHigh, __in DWORD dwFileOffsetLow, __in SIZE_T dwNumberOfBytesToMap
Trang 1BÁO CÁO TH C HÀNH ỰC HÀNH
MÔN H C : H ĐI U HÀNHỌC : HỆ ĐIỀU HÀNH Ệ ĐIỀU HÀNH ỀU HÀNH
Tp H Chí Minh ,tháng 12 năm 2009ồ Chí Minh ,tháng 12 năm 2009
Tác gi : Tr n Th Toàn ả : Trần Thế Toàn ần Thế Toàn ế Toàn
1 Nội dung bài tập thực hành :
Bài a6 : Viết chương trình giao tiếp giữa hai tiến trình bằng cách sử dụng shared memory Tiến trình A gửi 1 thông điệp(message ) sang tiến trình B
và đợi tiến trình B phản hồi Tiến trình B đợi thông điệp từ tiến trình A , sau
đó phản hồi thông điệp cho tiến trình A
2 Hướng giải quyết cho bài tập :
Ta dùng cơ chế shared-memory thông qua memory mapped files
Hai tiến trình tham gia vàp quá trình giao tiếp là Proccess P0 và Process P1 Trong đó , đầu tiên P0 sẽ tạo ra File-mapping object , và chia sẻ
file-mapping object này cho P1 thông qua tên của File-file-mapping object P0 liên kết với File-mapping Object này trên cơ sở tạo ra một view trên vùng nhớ được liên kết tới , nhờ P0 tạo 1 view riêng cho mình rồi map tới file được chia sẻ
P1 không tạo File-mapping Object nữa , nó sử dụng File-mapping object do P0 tạo ra , P1 mở file mapping object và tạo 1 view riêng của nó , map vùng nhớ của tiến trình tới vùng dữ liệu chia sẻ giữa P0 và P1
Sau khi việc chia sẻ vùng nhớ chung đã hoàn thành , ta tiến hành việc thực hiện giao tiếp giữa hai tiến trình ( hay có thể gọi là “chat” ).Tiến trình P0 sau khi tạo ra vùng dữ liệu chia sẻ , P1 sẽ mở 1 view lên vùng dữ liệu chia
sẻ này , và sẽ là tiến trình giao tiếp trước Sau khi P1 gửi thông điệp tới P0 , P1 sẽ không còn khả năng gửi tiếp thông điệp nữa mà nó phải chờ P0 hồi đáp lại 1 thông điệp
Việc giao tiếp giữa 2 tiến trình sẽ kết thúc nếu có bất kì bên nào nhập vào từ khóa “exit” , sau đó ấn Enter
3 Cài đặt bài toán trên ngôn ngữ lập trình C :
a Tiến trình P0 :
Trang 2Bước 1 : Tạo File-mapping Object
hMapFile có kiểu HANDLE là giá trị trả về của hàm
CreateFileMapping(…)
HANDLE WINAPI CreateFileMapping(
in HANDLE hFile,
in LPSECURITY_ATTRIBUTES lpAttributes,
in DWORD flProtect,
in DWORD dwMaximumSizeHigh,
in DWORD dwMaximumSizeLow,
in LPCTSTR lpName
);
Trong đó , tham số thứ nhất là HANLDE hFile , do yêu cầu của chương trình không yêu cầu lưu lại chat-log , để đơn giản cho chương trình , ta đưa vào giá trị
lên 1 file trên Disk , ta sẽ tạo một file-mapping Object lên Paging-File trong bộ nhớ
Với dòng lệnh trên ta tạo ra một File Mapping Object được xác định bởi
MapObjName , được chia sẻ với thuộc tính PAGE_READWRITE
Bước 2 :
Sau đó , ta tạo 1 view của P0 tới file – mapping
LPVOID WINAPI MapViewOfFile(
in HANDLE hFileMappingObject,
in DWORD dwDesiredAccess,
in DWORD dwFileOffsetHigh,
hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL ,
PAGE_READWRITE ,0 , BUF_SIZE , MapObjName );
pBuf = (LPCTSTR)MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS , 0 ,
0 , BUF_SIZE);
Trang 3in SIZE_T dwNumberOfBytesToMap
);
Kết quả là hàm sẽ trả về 1 con trỏ tới tới đầu block bộ nhớ của mapping view Con trỏ pBuf sau này sẽ được ta dùng để ghi và đọc thông điệp từ vùng nhớ chia
sẻ
Bước 3 :
Chương trình bước vào vòng lặp vô cùng while(1) với hai thao tác đọc thông tin từ vùng nhớ chia sẻ , in lên màn hình và ghi thông tin lên vùng nhớ chia sẻ
Việc đọc thông tin và ghi thông tin của tiến trình P0 và P1 được điều khiển bởi vùng nhớ chia sẻ thứ hai trong chương trình mà đại diện cho giá trị của vùng nhớ
là biến turn Trong vòng lặp while(1) bên trong vòng lặp while(1) lớn , ta liên tục thực hiện việc kiểm tra xem đã tới lượt P0 thực hiện đọc thông trong vùng nhớ chia
sẻ ra và in thông tin đó lên màn hình hay chưa :
Chỉ khi thỏa điều kiện biến turn mang giá trị 0 thì P0 mới thực hiện việc đọc thông tin của mình Với giá trị biến turn bằng 0 nghĩa là P1 đã thực hiện xong việc ghi thông điệp vào vùng nhớ chia sẻ
Bước 5 :
while (1)
{
turn = atoi(BufferOut);
{
if (inb != "")
printf(inb);
break ; }
}
Trang 4Sau khi thực hiện xong việc đọc thông tin từ vùng nhớ chia sẻ và in lên màn hình , tới lượt P0 được truyền đi thông điệp của nó Chương trình thực thi câu lệnh
fgets() có tác dụng lấy nội dung phím gõ vào từ vùng đệm bàn phím và lưu vào trong đệm outb Nếu chuỗi nhập vào là “exit\n” thì chương trình sẽ thoát khỏi quá trình giao tiếp .Ta thực hiện việc ghi thông tin lấy từ vùng đệm bàn phím lên vùng nhớ chia sẻ
Để đảm bảo thông điệp sau khi được P0 cập nhập thì ta phải được P1 “ phát hiện”
ra và in lên màn hình , ta sử dụng một cơ chế đồng bộ riêng sẽ được mô tả chi tiết
ở phần tiếp theo của báo cáo này
Ta thực hiện việc cập nhật vùng nhớ điều khiển sau khi đã tiến hành ghi thông tin lên vùng nhớ chia sẻ
Vòng lặp của chương trình cứ tiếp tục thực hiện
Các thao tác kết thúc chương trình bao gồm UnmapViewOfFile và CloseHandle để tránh memory-leakage
b Tiến trình P1 :
Về cơ bản thì các cài đặt trong P1 tương tự như P0 , ta sẽ lượt sơ qua các thao tác chính để thấy sự giống nhau này :
Trong vòng lặp while(1) , chương trình sẽ lần lượt thực hiện qua các thao
fgets(outb , BUF_SIZE , stdin);
{
printf("\nChuong trinh dang thoat !\n");
strcpy(outb , "");
exit(1);
}
itoa(1 , BufferIn , 10);
Trang 5Bước 1 : OpenFileMapping() trên file-mapping Object do P0 tạo ra trước Bước 2 : Tạo một view lên vùng nhớ chia sẻ , giá trị trả về là 1 con trỏ , trỏ tới địa chỉ đầu tiên trong vùng nhớ chia sẻ Với thao tác này ta đã map vùng nhớ của P1 tới vùng nhớ chia sẻ chung giữa P0 và P1
Bước 3 : Tương tự như P0 , ta cũng lần lượt thực hiện hai thao tác , đó là đọc thông tin trong vùng nhớ chia sẻ lên màn hình và ghi thông tin lên vùng nhớ chia sẻ thông qua bộ đệm bàn phím
Cuối cùng là các thao tác kết thúc chương trình để tránh Memory-leakage
c Cơ chế đồng bộ hóa giữa hai tiến trình P0 va P1 :
Vấn đề đặt ra :
Khi P1 bắt đầu phiên giao tiếp với P0 , sau khi P1 gửi một thông điệp
sang P0 thì P0 ” nhận thấy được ” ( detect ) và biết được tới lượt nó đọc
thông điệp lên màn hình và gửi ngược lại 1 thông điệp khác P1 để duy trì giao tiếp Mặt khác, sau khi 1 tiến trình đã gửi thông điệp đi rồi , nó không có quyền tiếp tục gửi thông điệp đi nữa
Giải quyết vấn đề :
Ta sử dụng 1 biến turn là thể hiện của vùng nhớ chia sẻ thực hiện việc đồng bộ giữa hai tiến trình
Vùng nhớ chia sẻ này dùng cơ chế Memory-mapped file , thông qua điều khiển hFlag :
Với vùng nhớ chia sẻ được tạo ra này , ta thực hiện cập nhật 2 giá trị 0 và 1 tùy theo P1 hay P0 Với giá trị tương ứng của vùng nhớ mà đại diện là biến turn ,
ta có thể quyết định việc đọc thông điệp và ghi thông điệp lên màn hình , cũng như gửi thông điệp giao tiếp là thuộc về tiến trình nào ? P0 hay P1
pBuf =(LPCTSTR) MapViewOfFile(hMapFile , FILE_MAP_ALL_ACCESS,
0,0, BUF_SIZE);
hFlag = CreateFileMapping(INVALID_HANDLE_VALUE , NULL ,
PAGE_READWRITE , 0 , BUF_SIZE , Flag);
Trang 6Trước tiên , P0 tạo ra vùng nhớ chia sẻ này , nhưng ta muốn rằng P1 phải là tiến trình đầu tiên thực hiện việc gửi thông điệp cho P0 , ta gán giá trị cho vùng nhớ ban đầu là 1
Như vậy khi P0 bắt đầu vòng lặp kiểm tra việc đọc thông tin trong vùng nhớ chia sẻ và ghi lên màn hình , nó sẽ bị kẹt trong vòng lặp đó
Chỉ đến khi nào turn có giá trị là 0 , và việc in thông điệp ra màn hình được thực thi thì P0 mới thoát khỏi vòng lặp này (Tại đây nảy sinh vấn đề lãng phí tài
nguyên mà ta sẽ nói tới sau )
Sau khi P0 thực hiện việc ghi thông điệp vào vùng nhớ chia sẻ , nó sẽ thay đổi giá trị trong vùng nhớ điều khiển , như vậy P1 trong khi chạy liên tục vòng lặp kiểm tra biến turn để kiểm tra tới lượt P1 chưa sẽ “phát hiện” ra sự thay đổi giá trị biến
turn trong P1 , nó sẽ tiến hành đọc thông điệp lên màn hình , sau đó lại ghi thông
//Khoi gan luot doc thong tin dau tien la cua Process 1.
itoa(1 , BufferIn , 10);
while (1)
{
turn = atoi(BufferOut);
{
if (inb != "")
printf(inb);
break ; }
}
//Thay doi gia tri trong vung nho dieu khien.
itoa(1 , BufferIn , 10);
Trang 7điệp lên vùng nhớ chia sẻ , rồi lại thay đổi giá trị trong vùng nhớ điều khiển Cứ như vậy quá trình giao tiếp diễn ra
4 Các vấn đề còn tồn tại của giải pháp đã đưa ra :
Cơ chế “lắng nghe” giữa hai tiến trình được cài đặt bằng vòng lặp while ()
Do vậy , cả hai tiến trình liên tục kiểm tra xem nó đã có quyền đọc thông tin lên màn hình hay chưa , chính cơ chế Busy-waiting này thực sự làm tiêu tốn tài nguyên của máy tính trong khi chạy cả 2 tiến trình
Giải pháp : Dùng cơ chế Sleep-and-wakeup , thông qua việc dùng
semaphore
5 Tài liệu tham khảo :
- Operating System Concepts 6th edition by Silberchart Galvin Gagne
ISBN : 9812-53-055X
- Windows System Progamming 3rd edition by Johnson M.Hart
ISBN : 0-321-25619-0
- Microsoft Development Network ( MSDN Library )