Thủ tục pthread_detach() có thể được sử dụng để tách một thread thậm chí
thread đó được tạo ra với thuộc tính là có thể nối được.Không có thủ tục ngược lại. Ví dụ về nối thread: #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 4 void *BusyWork(void *t) { int i; long tid; double result=0.0; tid = (long)t; printf("Thread %ld starting...\n",tid); for (i=0; i<1000000; i++)
{
result = result + sin(i) * tan(i); }
printf("Thread %ld done. Result = %e\n",tid, result); pthread_exit((void*) t);
}
int main (int argc, char *argv[]) {
Sinh viên: Cấn Việt Dũng 27 Lớp : K51CHTTT pthread_t thread[NUM_THREADS]; pthread_attr_t attr; int rc; long t; void *status;
/* Initialize and set thread detached attribute */ pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t=0; t<NUM_THREADS; t++) {
printf("Main: creating thread %ld\n", t);
rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1);
} }
/* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++) { rc = pthread_join(thread[t], &status); if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1);
}
printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status); }
printf("Main: program completed. Exiting.\n"); pthread_exit(NULL);
Sinh viên: Cấn Việt Dũng 28 Lớp : K51CHTTT 2.2.7. Quản lý stack 2.2.7.1. Những thủ tục Pthread_attr_getstacksize(attr, stacksize) Pthread_attr_setstacksize(attr, stacksize) Pthread_attr_getstackaddr(attr, stackaddr) Pthread_attr_setstackaddr(attr, stackaddr) 2.2.7.2. Ngăn ngừa những vấn đề với stack
Chuẩn POSIX không quy định kích thước stack của một thread. Điều này phụ
thuộc và thực hiện khác nhau. Vượt giới hạn mặc định của stack rất dễ làm, với một kết quả bình thường: chương trình chấm dứt hoặc dữ liệu bị hỏng. Một chương trình
an toàn và di động không phụ thuộc vào giới hạn mặc định của stack, nhưng thay vào đó, rõ ràng stack bố trí đủ cho mỗi thread bằng cách sử dụng thủ tục pthread_attr_setstacksize. Các thủ tục pthread_attr_getstackaddr và pthread_attr_setstackaddr có thể được sử dụng bởi những ứng dụng trong một môi
trường mà ởđó stack cho mỗi thread phải đặt ở một vài vùng cụ thể của bộ nhớ.
2.3. Biến Mutex
2.3.1. Khái niệm mutex
Mutex là viết tắt của “mutual exclusion”. Biến mutex là một trong những
phương tiện chính để thực hiện việc đồng bộ thread và cho việc bảo vệ việc chia sẻ
dữ liệu khi xảy ra nhiều lời viết. Một biến mutex hoạt động như một “khóa” bảo vệ
quyền truy cập vào một nguồn dữ liệu được chia sẻ. Khái niệm cơ bản của một
mutex được sử dụng trong Pthread là chỉ có một thread có thể khóa (hoặc sở hữu) một biến mutex tại bất kỳ thời điểm nào. Vì vậy, ngay cả khi nếu một vài thread cố
khóa một mutex thì chỉ một thread sẽ thành công. Không có thread khác có thể sở
hữu mutex đó cho tới khi thread sở hữu mở khóa mutex đó. Những thread phải thay phiên nhau tuy cập dữ liệu được bảo vệ. Mutex có thể được sử dụng để ngăn chặn
điều kiện tương tranh. Một ví dụ về điều kiện tương tranh liên quan đến một giao dịch ngân hàng được chỉ ra dưới đây:
Sinh viên: Cấn Việt Dũng 29 Lớp : K51CHTTT
Trong ví dụ trên, một mutex nên được sử dụng để khóa “balance” trong khi một thread đang sử dụng nguồn dữ liệu được chia sẻ này. Rất thường xuyên các hành động được thực hiện bởi một thread sở hữu một mutex là cập nhật các biến toàn cục. Đây là một cách an toàn đểđảm bảo rằng khi một vài thread cập nhật cùng biến này, giá trị cuối cùng là giống như những gì nó sẽ được nếu chỉ có một thread thực hiện cập nhật. Các biến đang được cập nhật thuộc về “critical section”.
Một trình tựthông thường trong việc sử dụng một mutex là như sau:
[1] Tạo ra và khởi tạo một biến mutex. [2] Một vài thread thử khóa mutex.
[3] Chỉ một thread thành công và thread đó sỡ hữu mutex. [4] Thread sở hữu thực hiện một vài tập các hành động. [5] Thread sở hữu mở khóa mutex.
[6] Một thread khác giành được mutex và lặp lại quá trình trên. [7] Cuối cùng mutex bị phá hủy.
Khi bảo vệ dữ liệu được chia sẻ, đó là trách nhiệm của người lập trình để đảm bảo mọi thread có nhu cầu sử dụng một mutex. Ví dụ, nếu bốn thread đang được cập nhật cùng dữ liệu, nhưng chỉ có một sử dụng mutex, dữ liệu vẫn có thể bị hỏng.
2.3.2. Tạo ra và phá hủy mutex 2.3.2.1. Những thủ tục
Pthread_mutex_init(mutex, attr)
Sinh viên: Cấn Việt Dũng 30 Lớp : K51CHTTT
Pthead_mutexattr_init (attr)
Pthread_mutexattr_destroy(attr)
2.3.2.2. Cách sử dụng
Biến mutex phải được khia bảo với kiểu pthread_mutex_t và phải được khởi tạo trước khi nó được sử dụng. Có hai cách để khởi tạo một biến mutex:
Theo cách tĩnh, khi nó được khai báo. Ví dụ: Pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZE.
Theo cách động, với thủ tục pthread_mutex_init(). Phương thức này cho phép thiết lập đối tượng thuộc tính mutex, attr.
Đối tương attr được sử dụng để thiết lập thuộc tính cho đối tượng mutex và phải là kiểu pthead_mutexattr_t nếu được sử dụng (có thế để là NULL nếu thiết lập mặc định). Chuẩn Pthread định nghĩa 3 thuộc tính tùy chọn cho mutex:
Protocol: Chỉ định giao thức được sử dụng để ngăn chặn sựđảo lộn ưu tiên cho một mutex.
Prioceiling: chỉđịnh trần ưu tiên của một mutex.
Process-shared: chỉđịnh quá trình chia sẻ một mutex.
Chú ý rằng không phải tất cả các thực hiện có thể cung cấp ba thuộc tính mutex tùy chọn. Các thủ tục pthead_mutexattr_init() và pthread_mutexattr_destroy() được dùng để
tạo ra và phá hủy đối tượng thuộc tính mutex tương ứng. Pthead_mutexattr_destroy() nên
được dùng để giải phóng đối tượng mutex khi nó không còn cần thiết.