Bài 45.126 phút đọc
pthread, create và join
Sau bài này bạn sẽ làm được
- Phân biệt luồng với tiến trình trên sáu tiêu chí
- Tạo và chờ luồng bằng pthread_create và pthread_join
- Tránh bẫy truyền địa chỉ biến vòng lặp
- Liên kết với cờ -pthread
Luồng là nhiều dòng thực thi trong cùng một tiến trình, chia sẻ bộ nhớ. Đó là sức mạnh và cũng là nguy hiểm của chúng. Chương này chạy được trên bản MinGW qua winpthreads, nên các bản ghi là kết quả thật.
#Luồng và tiến trình
| Tiến trình | Luồng | |
|---|---|---|
| Không gian địa chỉ | Riêng biệt | Chia sẻ |
| Tạo mới | Chậm (fork) | Nhanh |
| Giao tiếp | IPC: pipe, socket, bộ nhớ chia sẻ | Biến chung, trực tiếp |
| Một cái sập | Không ảnh hưởng cái khác | Sập cả tiến trình |
| Chuyển ngữ cảnh | Chậm | Nhanh |
| Đồng bộ hoá | Ít cần | Bắt buộc |
Luồng (thread)
Một dòng thực thi độc lập bên trong một tiến trình. Nhiều luồng của cùng tiến trình chia sẻ vùng mã, dữ liệu toàn cục, heap, và bảng mô tả tệp; nhưng mỗi luồng có ngăn xếp, thanh ghi, và
errno riêng.#create và join
tcj.c
#include <pthread.h>
#include <stdio.h>
void *cong_viec(void *arg) {
long id = (long)arg;
printf("Luong %ld dang chay\n", id);
return (void *)(id * 10); /* gia tri tra ve */
}
int main(void) {
pthread_t t[4];
for (long i = 0; i < 4; ++i)
if (pthread_create(&t[i], NULL, cong_viec, (void *)i) != 0) {
perror("pthread_create");
return 1;
}
for (int i = 0; i < 4; ++i) {
void *kq;
pthread_join(t[i], &kq); /* cho luong xong, lay ket qua */
printf("Luong %d tra ve %ld\n", i, (long)kq);
}
return 0;
}terminal
gcc -O2 -pthread tcj.c -o tcj.exe && ./tcj.exe
Luong 0 dang chay Luong 1 dang chay Luong 3 dang chay Luong 2 dang chay Luong 0 tra ve 0 Luong 1 tra ve 10 Luong 2 tra ve 20 Luong 3 tra ve 30
#Giá trị trả về
Trả về và nhận qua void *
void *cong_viec(void *arg) {
long id = (long)arg;
return (void *)(id * 10); /* dong goi ket qua vao void* */
}
void *kq;
pthread_join(t[i], &kq); /* nhan qua con tro toi void* */
long gia_tri = (long)kq; /* mo goi */
/* Ham luong nhan MOT void* va tra MOT void*. De truyen so nguyen,
ep qua (void*) va nguoc lai. De truyen cau truc, truyen con tro
toi no.
CAN THAN: KHONG tra ve con tro toi bien CUC BO cua ham luong: */
void *sai(void *a) {
(void)a;
int ket_qua = 42;
return &ket_qua; /* SAI: ket_qua bien mat khi ham xong */
}
/* Ngan xep cua luong bi giai phong khi ham tra ve, nen con tro
tro toi vung da bi thu hoi. Dung con tro toi bien tinh, heap,
hoac ep gia tri truc tiep qua void*. */#Bẫy truyền tham số
arg.c, bẫy truyền địa chỉ biến vòng lặp
#include <pthread.h>
#include <stdio.h>
void *in(void *a) { printf("%d ", *(int *)a); return NULL; }
int main(void) {
pthread_t t[4];
printf("SAI (truyen &i): ");
for (int i = 0; i < 4; ++i)
pthread_create(&t[i], NULL, in, &i); /* SAI: moi luong tro toi CUNG i */
for (int i = 0; i < 4; ++i) pthread_join(t[i], NULL);
printf("\nDUNG (ban sao): ");
int args[4];
for (int i = 0; i < 4; ++i) {
args[i] = i; /* moi luong mot ban sao rieng */
pthread_create(&t[i], NULL, in, &args[i]);
}
for (int i = 0; i < 4; ++i) pthread_join(t[i], NULL);
printf("\n");
return 0;
}terminal
gcc -O0 -pthread arg.c -o arg.exe && ./arg.exe
SAI (truyen &i): 3 4 4 4 DUNG (ban sao): 0 1 2 3
Tự làm thử
- Tạo bốn luồng, mỗi luồng in số của nó, và chờ tất cả bằng
pthread_join. - Cho mỗi luồng trả về một giá trị và in giá trị đó ở luồng chính.
- Quên
-pthreadkhi liên kết và đọc lỗi. - Tái hiện bẫy
&i, chạy nhiều lần, và quan sát kết quả khác nhau. - Trả về con trỏ tới biến cục bộ của hàm luồng và quan sát hậu quả với công cụ phát hiện lỗi bộ nhớ.
- Tạo một luồng
detachvà giải thích khi nào dùng nó thay vìjoin.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
- Luồng chia sẻ bộ nhớ của tiến trình; đổi lại một luồng sập giết cả tiến trình và đồng bộ là bắt buộc.
pthread_createtạo,pthread_joinchờ và lấy kết quả; liên kết với-pthread.- Truyền và nhận qua
void *; không trả con trỏ tới biến cục bộ của hàm luồng. - Mỗi luồng phải được
joinhoặcdetach, nếu không rò rỉ tài nguyên. - Không truyền
&icủa biến vòng lặp; cho mỗi luồng một bản sao riêng.