Một số vấn đề trong windows
12.5 ỨNG DỤNG SỬ DỤNG NHIỀU TIỂU TRÌNH:
Việc thiết lập các tiểu trình con hỗ trợ cho tiểu trình chính trong chương trình của ứng dụng cho phép ứng dụng đồng thời đáp ứng nhiều yêu cầu của người dùng. Các tiểu trình hỗ trợ có thể thực hiện các xử lý bên trong (tiểu trình xử lý nội – worker thread) hoặc trực tiếp nhận và thực hiện các yêu cầu của người dùng (tiểu trình giao diện– user interface thread).
12.5.1 Tiểu trình xử lý nội:
Tiểu trình xử lý nội đảm nhận các xử lý tính toán bên trong, không trực tiếp tương tác với người dùng. Việc thiết lập tiểu trình xử lý nội trong chương trình được thực hiện thông qua các nội dung sau đây:
Xây dựng hàm đảm nhận việc điều khiển toàn bộ hoạt động xử lý của tiểu trình (Thread Procedure). Hàm này có khai báo như sau:
UINT MyThreadProc ( LPVOID pParam );
pParam : Tham số duy nhất mà hàm điều khiển nhận được khi tiểu trình được kích hoạt.
) Khi kết thúc xử lý, hàm phải trảvề một giá trị số nguyên phản ánh tình trạng kết thúc của hàm. Thông thường, giá trị 0 trả về cho một kết thúc thành công, các giá trị khác 0 là các qui ước về hiện tượng lỗi. Thực hiện khởi động tiểu trình xử lý nội thông qua hàm sau:
CWinThread* AfxBeginThread (
AFX_THREADPROC pfnThreadProc, // Hàm điều khiển LPVOID pParam, // Tham số của hàm. int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0, DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
2Sau đây là bố cục thực hiện toàn bộ công việc trên: UINT MyThreadProc( LPVOID pParam ) { … // Khai thác nội dung của pParam … // Thực hiện các xử lý cần thiết. return ( có_lỗi ) ? 1 : 0;
}
… // Chuẩn bị khởi động tiểu trình
pInfo = new MyInfo ; // Chỉ đến vùng chứa các giá trị thông số AfxBeginThread( MyThreadProc, pInfo );
176 Lập trình Windows với MFC - Microsoft Visual C++ 6.0 - Lê Ngọc Thạnh - lntmail@yahoo.com
2 Giả sử cần thực hiện ứng dụng sau:
- Tiểu trình xử lý nội cài đặt bởi một hàm có nhiệm vụ thực hiện chạy dòng chữ trong hộp thông báo cho đến khi có tín hiệu ngừng.
- Tiểu trình giao diện quản lý dialog nhận yêu cầu người dùng:
à Mục Start Text Scrolling khởi động tiểu trình thực hiện chạy chữ. Mục chọn này sau đó đổi thành Stop Text Scrolling để điều khiển ngừng tiểu trình nói trên.
à Mục Close chấm dứt ứng dụng. Dự án của ứng dụng được thực hiện như sau:
Tạo dự án WorkerThread với giao diện chính là dialog.
Thực hiện các cài đặt sau cho lớp CWorkerThreadDlg làm giao diện: - Mở dialog resource, cài đặt các control sau:
- Hộp chứa dòng chữ chạy Static IDC_INFO - Nút lệnh cho phép chữ chạy | ngừng Button IDOK
- Thuộc tính public m_isTextScrolled kiểu BOOL ghi nhận thông tin về hoạt động chạy chữ.
- Hành vi OnInitDialog khởi động các thông số: BOOL CWorkerThreadDlg::OnInitDialog() {
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon
m_isTextScrolled = FALSE; // Chưa thực hiện chạy chữ return TRUE;
}
- Hành vi OnOK ứng với nút lệnh IDOK thực hiện khởi động hoặc thông báo ngừng tiểu trình xử lý chạy chữ:
Một số vấn đề trong Windows 177
void CWorkerThreadDlg::OnOK() {
if (m_isTextScrolled) {
SetDlgItemText( IDOK, "Start Text Scrolling" ); // Đặt giá trị thông báo tiểu trình chạy chữ chấm dứt
m_isTextScrolled = FALSE; }
else {
SetDlgItemText(IDOK, "Stop Text Scrolling"); // Đặt giá trị cho phép cho tiểu trình chạy chữ thực hiện
m_isTextScrolled = TRUE;
// Khởi động tiểu trình với tham số là dialog giao diện AfxBeginThread( TextScrolling, this );
} }
TextScrolling là hàm xử lý của tiểu trình chạy chữ. Hàm nhận tham số void* là con trỏ chỉ đến đối tượng dialog giao diện. Có thể khai báo hàm trong phần cài đặt của lớp CWorkerThreadDlg để tiện sử dụng. UINT TextScrolling(void* pParam) {
// Con trỏ pParam thực chất là con trỏ đối tượng dialog giao diện CWorkerThreadDlg* pDlg = (CWorkerThreadDlg*)pParam; static CString info = " Welcome to multi-thread programming"; while (pDlg->m_isTextScrolled) {
// Giá trị thông báo cho phép tiểu trình tiếp tục thực hiện: info = info.Mid(1) + info.Left(1);
pDlg->SetDlgItemText(IDC_INFO, info); Sleep(100); // Tạm nghỉ }
return 0; // Kết thúc tiểu trình xử lý nội }
Biên dịch và chạy thử ứng dụng. 12.5.2 Tiểu trình giao diện:
Tiểu trình giao diện có khả năng trực tiếp nhận và xử lý yêu cầu của người dùng một cách độc lập với tiểu trình chính (cũng là tiểu trình giao diện) của ứng dụng. Việc thiết lập tiểu trình giao diện trong chương trình được thực hiện thông qua các nội dung sau đây:
178 Lập trình Windows với MFC - Microsoft Visual C++ 6.0 - Lê Ngọc Thạnh - lntmail@yahoo.com
Chuẩn bị giao diện (cửa sổ hoặc dialog) của tiểu trình giao diện. Xây dựng lớp kế thừa từ CWinThread để quản lý tiểu trình giao diện.
Sử dụng giao diện trên cho lớp thông qua hành vi InitInstance của lớp. Thực hiện khởi động tiểu trình giao diện thông qua hàm sau:
CWinThread* AfxBeginThread ( CRuntimeClass* pThreadClass,
int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
pThreadClass : Con trỏ đến cấu trúc quản lý thông tin thi hành của lớp đối tượng quản lý tiểu trình giao diện được kích hoạt. Xem (11.4). 2 Giả sử có yêu cầu thực hiện ứng dụng với hai giao diện hoạt động đồng hành; giao diện Sub Interface of program được kích hoạt khi người dùng click chọn mục Run the sub user-interface thread dialog trên dialog giao diện của tiểu trình giao diện chính.
Các bước thực hiện như sau:
Tạo dự án UserIntThread với giao diện chính là dialog.
Thiết kế dialog resource cho giao diện con. Trên dialog resource này, cài nút thoát với số hiệu IDCANCEL.
Bổ sung lớp CSubUserDlg kế thừa từ CDialog sử dụng resource trên. Bổ sung lớp đối tượng CSubUserThread kế thừa từ CWinThread cho
phép quản lý các tiểu trình giao diện con. Đối tượng CSubUserThread nhận đối tượng CSubUserDlg làm cửa sổ giao diện chính thông qua hành vi InitInstance của nó.
Một số vấn đề trong Windows 179
BOOL CSubUserThread::InitInstance() { CSubUserDlg dlg; m_pMainWnd = &dlg; dlg.DoModal(); return TRUE; }
Thực hiện các cài đặt sau cho lớp dialog CUserIntThreadDlg: - Mở dialog resource, cài đặt các control sau:
- Nút lệnh kích hoạt tiểu trình giao diện con Button IDOK
- Nút lệnh kết thúc ứng dụng Button IDCANCEL - Hành vi OnOK cho nút chọn IDOK kích hoạt tiểu trình giao diện:
void CUserIntThreadDlg::OnOK() { AfxBeginThread( RUNTIME_CLASS(CSubUserThread) ); } Biên dịch và chạy thử ứng dụng. 12.5.3 Các hàm hỗ trợ: void AfxEndThread (
UINT nExitCode // Giá trị kết thúc tiểu trình
}; Chấm dứt hoạt động của tiểu trình. Hàm chỉ được sử dụng trong phần cài đặt xử lý của tiểu trình.
BOOL GetExitCodeThread (
HANDLE hThread, // Handle của tiểu trình
LPDWORD lpExitCode // Con trỏ đến biến chứa kết quả.
); Lấy giá trị kết thúc của một tiểu trình. Trả về giá trị TRUE nếu tác vụ thực hiện thành công.
hThread của một tiểu trình có thể lấy từ thuộc tính m_hThread của đối tượng CWinThread quản lý tiểu trình.