POSIX Thread (1)
Biết cách lập trình với thread và multithread là một trong những kỹ năng cần thiết của một programmer tốt. Trong bài viết này sẽ đề cập về POSIX (Portable Operating System Interface) threads. Như bạn đã biết POSIX (chính xác hơn là chuẩn IEEE 1003.1c của tổ chức IEEE đưa ra) bao gồm những định nghĩa “giao diện” chung cho các hệ điều hành. Điều đó có nghĩa là những hệ điều hành nào support POSIX (GNU/Linux, BSD, Sun Solaris, Unix, …) thì đều có những system call có prototype giống như trong tài liệu về POSIX đưa ra, mặc dù đối với mỗi hệ điều hành có cách implement khác nhau. POSIX threads (Pthreads) là một cách rất tốt để làm tăng độ tin cậy và performance cho chương trình.
Threads cũng tương tự như processes, đều được phân chia thời gian bởi kernel. Với hệ thống chỉ có một bộ vi xử lý thì kernel sử dụng cách phân chia thời gian để “làm cho” các threads như là chạy đồng thời theo cùng cách thức kernel thực hiện với processes. Và với các hệ thống đa nhân thì các threads thực sự có thể chay đồng thời giống như là nhiều processes.
Thế thì tại sao multithread lại được ưa chuộng hơn là nhiều process độc lập đối với các task có mối quan hệ với nhau? Đó là bởi vì các threads sử dụng chung cùng một không gian bộ nhớ. Mỗi thread độc lập đều có thể truy nhập vào cùng một biến toàn cục trong bộ nhớ. Trong khi fork() cho phép tạo ra nhiều process nhưng rất khó khăn trong việc trao đổi thông tin giữa process với nhau vì mỗi process có một không gian vùng nhớ riêng. Không có một câu trả lời đơn giản cho việc trao đổi giữa các process (IPC). Do vậy mà multiprocess programming sẽ phải chịu 2 trở ngại lớn:
- Perforamance thấp vì khi tạo một process mới đòi hỏi kernel thực thi nhiều phép tính toán để cấp phát bộ nhớ.
- Trong hầu hết các trường hợp thì IPC làm chương trình trở nên phức tạp hơn rất nhiều.
Hơn thế nữa, quá tải và sự phức tạp không phải là những thứ tốt. Nếu bạn đã từng phải làm những thay đổi lớn cho một chương trình của bạn mà support IPC, sẽ rất tốt nếu sử dụng cách tiếp cận chia sẻ vùng nhớ đơn giản của threads. Pthreads không cần phải những lời gọi expensive và phực tạp bởi vì threads “sống cùng một ngôi nhà”. Bạn không phải đẩy dữ liệu thông qua một file hoặc một vùng nhớ nào đó. Chính vì lý do này mà bạn nên cân nhặc mô hình một process/nhiều threads hơn là nhiều process/một thread.
Như đã nói ở trên, tạo một thread nhanh hơn rất nhiều (từ 10 cho đến 100 lần) so với tạo một process. Kernel không cần phải tạo một bản copy độc lập của không gian bộ nhớ hiện thời, bảng các mô tả file (file descriptors). Điều đó tiết kiệm rất nhiều thời gian của CPU. Chúng ta sẽ xem xét một ví dụ.
==============================================================================
C Code for fork() creation test
==============================================================================
#define NFORKS 50000
void do_nothing()
{
int i;
i= 0;
}
main()
{
int pid, j, status;
for (j=0; j<NFORKS; j++) {
/*** error handling ***/
if ((pid = fork()) < 0 ) {
printf ("fork failed with error code= %d\n", pid);
exit(0);
}
/*** this is the child of the fork ***/
else if (pid ==0) {
do_nothing();
exit(0);
}
/*** this is the parent of the fork ***/
else {
waitpid(pid, status, 0);
}
}
}
==============================================================================
C Code for pthread_create() test
==============================================================================
#include <pthread.h>
#define NTHREADS 50000
void *do_nothing(void *null)
{
int i;
i=0;
pthread_exit(NULL);
}
main()
{
int rc, i, j, detachstate;
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for (j=0; j<NTHREADS; j++) {
rc = pthread_create(&tid, &attr, do_nothing, NULL);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
/* Wait for the thread */
rc = pthread_join(tid, NULL);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
}
pthread_attr_destroy(&attr);
pthread_exit(NULL);
}
Hãy chạy 2 chương trình đó và so sánh. Xem thêm kết quả so sánh ở site này: http://www.llnl.gov/computing/tutorials/pthreads/
Tuy nhiên thì multithread cũng có điểm yếu nhất định. Đó chính là khả năng đổ vỡ của nó. Bởi vì các threads ở trong cùng một không gian bộ nhớ nên nếu một thread đổ vỡ (crash) sẽ kéo theo toàn bộ process và các thread khác bị terminate. Trái lại thì khi một process bị đổ vỡ thì không ảnh hưởng gì đến các process khác. Chính vì vậy ở những hệ thống lớn thì họ lại sử dụng các daemon là multiprocess hơn là multithread.
Reference: del.icio.us/hoangtran/multithread
Viết mà chẳng giải thích nhiệm vụ của từng hàm gì cả
Chào! ko chú thích code làm sao người đọc hiểu được đây bạn
Dầy mà ko hiểu nữa … thì sao đây ?
mình mới học về hệ điều hành! nên có rất nhiều điều không biết! Mong bạn có thể có những bài căn bản để cho mình dễ hiểu.
thanks. đang đuối môn điều hành. đọc cái này như với được một cục xốp nhưng phía trước vẫn là con đường xuyên đại dương