Professional Documents
Culture Documents
Bai 7 - Xu Ly Da Luong
Bai 7 - Xu Ly Da Luong
luồng
1
Nội dung bài học
n Xử lý đa luồng là gì?
n Ví dụ về xử lý đa luồng
n Các vấn đề liên quan đến đồng bộ hóa
2
Xử lý đồng thời có luôn tốt hơn xử lý
tuần tự ?
process process
request 1 request 2
3/2c+p
NO!
Create Create per request
concurrent slave1 slave2
0 c 2c 2c+p
3/2p
process process per request
iterative request 1 request 2
0 2p
3
Vấn đề của hàm fork()
Stack
4
Giải pháp
n Xử lý đa luồng
5
Luồng là gì ?
n Thread (luồng) là một dòng điều khiển trong một tiến
trình
q Tiến trình nhẹ (lightweight process)
q có riêng
n Định danh luồng (thread ID)
n Bộ đếm chương trình (PC)
n Tập thanh ghi (register set)
n Ngăn xếp (stack): chứa các biến cục bộ
n Độ ưu tiên
q Có chung
n Phần mã chương trình
n Phần dữ liệu
n Tài nguyên hệ điều hành
6
Tại sao lại là xử lý đa luồng?
7
Đa xử lý và đa luồng
Three processes with one thread each
8
Khởi tạo luồng mới
Process A
Thread 1
Global pthread_create()
Variables
Process A
Code Thread 2
Program Program
counter counter
Stack Stack
9
pthread_create(): Khởi tạo luồng
#include <pthread.h>
int pthread_create(pthread_t *tid, const pthread_attr_t *attr,
void *(*func) (void *), void *arg);
Returns: 0 if OK, positive Exxx value on error
n tid: con trỏ tới biến định danh luồng kiểu pthread_t
q pthread_t: thường là unsigned int
10
Tuổi sống của một luồng
n Khi một luồng được tạo ra, nó sẽ chạy hàm func() được
thiết lập trong lệnh gọi pthread_create().
n Khi hàm func() trả về giá trị, luồng sẽ kết thúc thực thi
n Một luồng cũng có thể kết thúc thực thi bằng hàm
pthread_exit().
n Nếu luồng chính kết thúc thực thi hoặc một luồng nào đó
trong tiến trình gọi lệnh exit() thì tất cả các luồng khác
đều kết thúc thực thi
#include <pthread.h>
void pthread_exit (void *status);
11
Luồng con phụ thuộc(joinable)/Luồng
con độc lập (detached)
n Luồng con phụ thuộc
q Sau khi xử lý của luồng kết thúc, trạng thái và ID
của luồng con vẫn được giữ lại trong bộ nhớ cho
đến khi hàm pthread_join được gọi
q Trạng thái của một luồng khi được tạo ra sẽ được
mặc định là phụ thuộc (joinable)
n Luồng con độc lập
q Trạng thái và ID của luồng con sẽ được xóa ra
khỏi bộ nhớ sau khi xử lý của luồng kết thúc
12
pthread_join(): đợi một luồng phụ thuộc
dừng thực thi
#include <pthread.h>
n tid: thread ID
n status: con trỏ tới giá trị trả về từ luồng
n Tương đương với hàm waitpid trong xử lý
đa tiến trình
13
pthread_detach(): chuyển một luồng sang
trạng thái “độc lập” (deteched)
#include <pthread.h>
n tid: thread ID
n Khi một luồng độc lập kết thúc thực thi, tất cả
tài nguyên của nó sẽ được giải phóng
14
pthread_self():Lấy định danh của chính
luồng đó
#include <pthread.h>
15
Máy chủ xử lý đồng thời đa luồng hướng
kết nối
n Tạo mỗi luồng cho một kết nối mới đến máy
khách
16
master
Server
thread1 thread2 threadn
application
processes
18
Các bước thực thi máy chủ xử lý đồng
thới, hướng kết nối, đa luồng (2)
n Bước 1 luồng con: Thực thi hàm nhận và xử lý yêu
cầu của máy khách thông qua socket kết nối và gửi
trả lại kết quả trả lời
n Bước 2 luồng con: Đóng socket kết nối và kết thúc
thực thi
19
doit() function
static void *doit(void *arg)
{
pthread_detach(pthread_self());
str_echo(* ( ( int *) arg)); /* same function as before */
close(* ( ( int *) arg)); /* done with connected socket */
return (NULL);
}
20
Ví dụ về máy chủ TCP echo xử lý đồng thời đa
luồng
int main(int argc, char **argv){
int listenfd, connfd;
pthread_t tid;
socklen_t addrlen, len;
struct sockaddr cliaddr;
int *iptr;
for (; ; ) {
connfd = accept(listenfd, cliaddr, &len);
pthread_create(&tid, NULL, &doit, (void *) &connfd);
}
}
21
Vấn đề của xử lý đa luồng
n Thread-safe
q Nếu một hàm sử dụng biến toàn cục, có thể
không an toàn nếu sử dụng hàm này với đa luồng
q Một hàm là thread-safe nếu nó hoạt động đúng
khi được sử dụng tại nhiều luồng khác nhau
n Đồng bộ hóa bộ nhớ giữa các luồng
q Các luồng tranh chấp việc truy cập vào cùng một
tài nguyên
22
Thread Safe library functions
n POSIX.1 requires that all the functions defined by POSIX.1 and by
the ANSI C standard be thread-safe
n POSIX says nothing about thread safety with regard to the
networking API functions
Need not be thread-safe Must be thread safe
ctime ctime_r
rand rand_r
gethostXXX
getnetXXX
getprotoXXX
getservXXX
inet_ntoa
… …
23
Cải tiến với hàm thread-safe
int main(int argc, char **argv){
int listenfd;
pthread_t tid;
socklen_t addrlen, len;
struct sockaddr cliaddr;
int *iptr;
for (; ; ) {
iptr = malloc(sizeof(int));
*iptr = accept(listenfd, cliaddr, &len);
pthread_create(&tid, NULL, &doit, (void *) iptr);
}
}
24
static void *doit(void *arg)
{
int connfd;
25
Thread-Specific Data
n Dữ liệu riêng của luồng
q Quản lý vùng bộ nhớ riêng cho mỗi luồng
q đảm bảo các hàm là thread-safe
n Mỗi tiến trình duy trì một số lượng nhất định các thông tin về dữ liệu
riêng của luồng
q Theo POSIX, >= 128 Dữ liệu riêng hiện
q Câu trúc Key được dùng hay
không?
26
Thông tin về dữ liệu riêng tại mỗi luồng
27
Sử dụng dữ liệu riêng của luồng như thế
nào?
n Lấy chỉ số của dữ liệu riêng hiện đang trống từ cấu
trúc key và gán hàm giải phóng bộ nhớ
q pthread_key_create()
n Thường chạy trong hàm khởi tạo
q pthread_once()
n Tạo vùng dữ liệu và gán con trỏ vào dữ liệu riêng
q pthread_setspecific()
q Chỉ thực hiện một lần
n Lấy dữ liệu riêng
q pthread_getspecific()
28
Ví dụ về hàm readline
n threads/realine.c
29
Loại trừ lẫn nhau
n Các luồng chia xẻ bộ nhớ, xử lý file (file handles), sockets, và
các tài nguyên khác
n Nếu hai luồng muốn sử dụng cùng một tài nguyên tại một thời
điểm nào đó, một trong 2 luồng phải đợi luồng kia kết thúc việc
sử dụng tài nguyên
30
Ví dụ về sự cần thiết của loại trừ lẫn nhau
n threads/example01.c
count
increase increase
Thread1 Thread2
31
Loại trừ lẫn nhau (2)
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t * mptr);
int pthread_mutex_unlock(pthread_mutex_t * mptr);
Both return: 0 if OK, positive Exxx value on error
32
Ví dụ về loại trừ lẫn nhau
n threads/example02.c
33
Đặt vấn đề: Web client với nhiều kết nối
đồng thời
n Luồng chính tạo nhiều luồng con để
download nhiều đối tượng Web cùng một lúc
n Luồng chính đợi các luồng con kết thúc
download
q Tạo biến đếm số lượng luồng con đã thực hiện
xong ndone
q Khi luồng con kết thúc, tăng biến đếm ndone lên 1
q Luồng chính chờ đến khi biến đếm ndone khác 0
thì xử lý dữ liệu đọc được
34
Làm thế nào để luồng A theo dõi sự thay
đổi tại luồng B?
n Giải pháp
q Tạo một biến toàn cục X
q Luồng B update giá trị của biến X
q Luồng A đọc giá trị của biến X
n Vấn đề
q Luồng A phải tạo một vòng lặp để theo dõi biến X
=> Lãng phí CPU
35
Biến điều kiện Condition Variables
36
Với Web client với nhiều kết nối đồng
thời
n Luồng chính
q Khai báo biến trạng thái, biến đếm ndone, biến loại trừ
n pthread_cond_t ndone_cond =
PTHREAD_COND_INITIALIZER;
q Tạo các luồng con để download file
q Khi biến đếm bằng 0, luồng chính chờ tín hiệu từ luồng con
gửi qua biến trạng thái
n Luồng con
q Sau khi kết thúc download, tăng biến đếm ndone và gửi tín
hiệu qua biến trạng thái
n Luồng chính
q Xử lý dữ liệu download từ luồng con
37
Ví dụ
n threads/web03.c
38