Thảo luận Bài 5
+72
LeThanhQuang (I22B)
NguyenTrongTinh(I22A)
MaiNguyenThanhLong(I22A)
QuangMinhTuan(I22B)
NguyenThiMai(I22A)
NguyenThiNgocPhuoc(122A)
LeNgocTung (I22A)
LETHIANHDAO48(I22B)
lekhanhhoa(I22B)
NguyenVanQuoc (I22B)
HaTrungMinhPhuc(I22B)
NguyenBaoLoc70(I22A)
PhamThiThao (I22B)
DuongKhanhThanh(I22B)
nguyenhoanglam_I22B
phungvanduong24(I12A)
tranngochuy(I22B)
NguyenCaoDuong(I22B)
phanthanhcan(I22A)
DuongTrungQuan
tranvanminh82(I22A)
NguyenKhanhDuy18 (I22B)
TranQuangTien(I22A)
NguyenNgocDan(I22B)
TrỉnhToQuyen(I12A)
vivanbieu(I22B)
VanNhatDongGiang(I22A)
NguyenVanSang(I22A)
TranThienTam (I22A)
NguyenPhuongNhu(I22B)
HuynhHuuTai(I22A)
Dao Duy Thanh(I22B)
NguyenVanTu(I22A)
dangvannhan(I22A)
NguyenVanPhat(I22B)
TruongTranThanhTu(I22B)
VoMinhThang(I22B)
VoMinhDien(I22B)
MaiXuanSon (I22B)
NguyenHuuMinh80(I22B)
dangthihoangly(I12A)
NguyenTienDat (I22A)
truongtph.i11c
NguyenHoangThien(I22B)
TranDangKhoa(I22A)
LeThiKimNgan67(I11C)
TranVuSang (I22B)
HongGiaPhu (I22A)
BuiTrongHung41(I11C)
NgT.KimHuyen(I22A)
PhamXuanThieu (I22A)
LêAnhNgữ(I22A)
nguyenthithutrang (I11C)
PhamQuocCuong (I22A)
NguyenHuuThien159 (I22B)
BuiThucTuan(I22B)
cat
NguyenBacHoi(I22B)
NguyenNhatHuy64(I22B)
LeAnhToan48(I22B)
NguyenTanDat(I22B)
dangmonghai(I12A)
NguyenManhHuy(I22B)
NgoVanTuyen(I22B)
NguyenHoangKimVu (I11C)
ChauQuangCam (I22B)
NguyenQuocHuy (I22B)
NguyenQuangHuy(I22B)
NguyenThanhQuoc(I22A)
HuynhDucQuang(I22B)
HoangThanhThien(I22B)
Admin
76 posters
Trang 4 trong tổng số 8 trang
Trang 4 trong tổng số 8 trang • 1, 2, 3, 4, 5, 6, 7, 8
Luồng và Tiến Trình!!
Ta có 3 luồng trong đó gồm: 1 luồng chính và 2 luồng phụ
- Luồng chính có tác dụng đánh thức luồng phụ.
- Sử dụng chung tài nguyên, chạy chung 1 code.
- Tiến trình(chứa các luồng để vận hành).
- Lập trình đa luồng dễ hơn lập trình đa tiếng trình vì (tương tác phải truyền thông, liên lạc dùng chung tài nguyên giữa các luồng dễ hơn nhiều việc dùng chung các Tiến trình đa truyền thông..
- Tạo mới 1 luồng dễ dàng hơn vì có sắn Code.
VD:
- 1 chung cư chúng ta xây thêm 1 phòng.
- 1 nhà thêm một phòng.
- khó hơn nhiều việc xây một chung cư từ đầu và 1 căn nhà..
- Luồng chính có tác dụng đánh thức luồng phụ.
- Sử dụng chung tài nguyên, chạy chung 1 code.
- Tiến trình(chứa các luồng để vận hành).
- Lập trình đa luồng dễ hơn lập trình đa tiếng trình vì (tương tác phải truyền thông, liên lạc dùng chung tài nguyên giữa các luồng dễ hơn nhiều việc dùng chung các Tiến trình đa truyền thông..
- Tạo mới 1 luồng dễ dàng hơn vì có sắn Code.
VD:
- 1 chung cư chúng ta xây thêm 1 phòng.
- 1 nhà thêm một phòng.
- khó hơn nhiều việc xây một chung cư từ đầu và 1 căn nhà..
NguyenHuuMinh80(I22B)- Tổng số bài gửi : 8
Join date : 13/03/2013
Age : 35
Giải thích Code sản xuất - tiêu thụ đa luồng!
#include < stdio . h >
#include < conio . h >
#include < windows . h > // Sử dụng được hàm win32 API
#define BUFFER_SIZE 10 // định nghĩa một buffer có 10 khoang chứa
int buffer[BUFFER_SIZE];
int in=0; // giá trị vị trí xếp sản phẩm vào
int out=0;// giá trị vị trí lấy sản phẩm ra
int nextProduced=1;// biến trung gian, chứa số hiệu sản phẩm đầu tiên
void Producer(){ // nhà sản xuất
while (1){
// ... Sản xuất (nextProduced)
while(((in+1)%BUFFER_SIZE)==out);// khoang chứa đầy thì quẩn tại đây đến khi nào có chỗ trống
buffer[in]=nextProduced++; // cho sản phẩm vào mảng tại vị trí in
in=(in+1)%BUFFER_SIZE; //sau khi chèn, tăng in lên 1, nếu in đang nằm ở vị trí cuối mảng sẽ nhảy về đầu mảng
SuspendThread(GetCurrentThread()); //getcureentthread: hàm của thư viện win32 API, trả về giá trị mục quản của luồng hiện hành, vd: 1700. SuspendThread(): ngừng luồng có mục quản là giá trị trong ngoặc, vd: SuspendThread(1700) ngừng luồng có mục quản 1700
}
}
void Consumer(){ // nhà tiêu thụ
int nextConsumed; // biến chứa sản phẩm được tiêu thụ
while (1){
while(in==out); //trong khoang chứa hết sản phẩm thì quẩn tại đây cho đến khi nào trong buffer có sản phẩm
nextConsumed=buffer[out]; //sản phẩm ở vị trí out được đưa vào biến netxconsumed
out=(out+1)%BUFFER_SIZE;//out tăng lên 1, nếu out đang nằm ở cuối mảng thì nhảy lên đầu mảng
// ... Tiêu thụ (nextConsumed)
Sleep(GetTickCount()%5000); // hàm gettickcount() sẽ trả về thời gian tính bằng ms trôi qua kể từ khi hệ thống khởi động tới thời điểm hiện tại, kết quả sẽ ra được con số rất lớn và chia lấy số dư cho 5000 sẽ được 1 con số từ 0-4999, cho luồng tiêu thụ này ngủ trong khoảng thời gian đó.
}
}
void ShowBuffer(){ // In nội dung Buffer
const char * LeftMargin="\n\t";
int i;
printf(LeftMargin);
for(i=0; i<(in*5);i++) putchar(' '); printf("!in");
printf(LeftMargin);
for (i=0; iprintf("S%2d, ",buffer[i]);
printf("S%2d",buffer[BUFFER_SIZE-1]);
printf(LeftMargin);
for(i=0; i<(out*5); i++) putchar(' ');printf("^out");
printf("\n");
}
int main(){
HANDLE ProducerHandle1, ProducerHandle2; // lưu mục quản của 2 nhà sx vào 2 biến ProducerHandle1, ProducerHandle2
HANDLE ConsumerHandle1, ConsumerHandle2; //lưu mục quản của 2 nhà tiêu thụ
DWORD ProducerID1, ProducerID2; // mã số định danh của luồng sản xuất
DWORD ConsumerID1, ConsumerID2; // mã số định danh của luồng tiêu thụ
// tạo 2 luồng sản xuất trong trạng thái ngủ
ProducerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4,&ProducerID1);// các đối số đầu ko quan tâm vì có mới chạy được
// số 4 chỉ ra luồng vừa tạo sẽ không chạy mà ngủ luôn, &ProducerID1 chỉ ra luồng sẽ có mã số định danh là ProducerID1
// sau khi làm lệnh này, sẽ có 2 luồng, luồng ctrinh này và luồng producer
ProducerHandle2=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4, &ProducerID2);
// Tạo 2 luồng tiêu thụ thi hành ngay
ConsumerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Consumer,0, 0, &ConsumerID1); //0: luồng tiêu thụ vận hành ngay, ko ngủ
ConsumerHandle2=CreateThread(0,0,
(LPTHREAD_START_ROUTINE)Consumer,
0, 0, &ConsumerID2);
while(1){
printf("\n- Nhap P/p de san xuat, 0 de ket thuc:”);
//P đánh thức nhà sx1, p sx2
switch (getch()){//biết người sử dụng bấm gì
case 'P':
ResumeThread(ProducerHandle1); //đánh thức luồng 1
break;
case 'p':
ResumeThread(ProducerHandle2);//đánh thức luồng 2
break;
case '0':
CloseHandle(ProducerHandle1);// hủy đối tượng(ở đây là luồng) có mục quản
CloseHandle(ProducerHandle2);
CloseHandle(ConsumerHandle1);
CloseHandle(ConsumerHandle2);
return 0;
}
Sleep(1);// ngủ 1 ms,(chờ in tăng lên 1) rồi mới showbuffer "Bước này không thực hiện thì kết quả sẽ bị sai".
ShowBuffer();
}
}[/quote]
#include < conio . h >
#include < windows . h > // Sử dụng được hàm win32 API
#define BUFFER_SIZE 10 // định nghĩa một buffer có 10 khoang chứa
int buffer[BUFFER_SIZE];
int in=0; // giá trị vị trí xếp sản phẩm vào
int out=0;// giá trị vị trí lấy sản phẩm ra
int nextProduced=1;// biến trung gian, chứa số hiệu sản phẩm đầu tiên
void Producer(){ // nhà sản xuất
while (1){
// ... Sản xuất (nextProduced)
while(((in+1)%BUFFER_SIZE)==out);// khoang chứa đầy thì quẩn tại đây đến khi nào có chỗ trống
buffer[in]=nextProduced++; // cho sản phẩm vào mảng tại vị trí in
in=(in+1)%BUFFER_SIZE; //sau khi chèn, tăng in lên 1, nếu in đang nằm ở vị trí cuối mảng sẽ nhảy về đầu mảng
SuspendThread(GetCurrentThread()); //getcureentthread: hàm của thư viện win32 API, trả về giá trị mục quản của luồng hiện hành, vd: 1700. SuspendThread(): ngừng luồng có mục quản là giá trị trong ngoặc, vd: SuspendThread(1700) ngừng luồng có mục quản 1700
}
}
void Consumer(){ // nhà tiêu thụ
int nextConsumed; // biến chứa sản phẩm được tiêu thụ
while (1){
while(in==out); //trong khoang chứa hết sản phẩm thì quẩn tại đây cho đến khi nào trong buffer có sản phẩm
nextConsumed=buffer[out]; //sản phẩm ở vị trí out được đưa vào biến netxconsumed
out=(out+1)%BUFFER_SIZE;//out tăng lên 1, nếu out đang nằm ở cuối mảng thì nhảy lên đầu mảng
// ... Tiêu thụ (nextConsumed)
Sleep(GetTickCount()%5000); // hàm gettickcount() sẽ trả về thời gian tính bằng ms trôi qua kể từ khi hệ thống khởi động tới thời điểm hiện tại, kết quả sẽ ra được con số rất lớn và chia lấy số dư cho 5000 sẽ được 1 con số từ 0-4999, cho luồng tiêu thụ này ngủ trong khoảng thời gian đó.
}
}
void ShowBuffer(){ // In nội dung Buffer
const char * LeftMargin="\n\t";
int i;
printf(LeftMargin);
for(i=0; i<(in*5);i++) putchar(' '); printf("!in");
printf(LeftMargin);
for (i=0; iprintf("S%2d, ",buffer[i]);
printf("S%2d",buffer[BUFFER_SIZE-1]);
printf(LeftMargin);
for(i=0; i<(out*5); i++) putchar(' ');printf("^out");
printf("\n");
}
int main(){
HANDLE ProducerHandle1, ProducerHandle2; // lưu mục quản của 2 nhà sx vào 2 biến ProducerHandle1, ProducerHandle2
HANDLE ConsumerHandle1, ConsumerHandle2; //lưu mục quản của 2 nhà tiêu thụ
DWORD ProducerID1, ProducerID2; // mã số định danh của luồng sản xuất
DWORD ConsumerID1, ConsumerID2; // mã số định danh của luồng tiêu thụ
// tạo 2 luồng sản xuất trong trạng thái ngủ
ProducerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4,&ProducerID1);// các đối số đầu ko quan tâm vì có mới chạy được
// số 4 chỉ ra luồng vừa tạo sẽ không chạy mà ngủ luôn, &ProducerID1 chỉ ra luồng sẽ có mã số định danh là ProducerID1
// sau khi làm lệnh này, sẽ có 2 luồng, luồng ctrinh này và luồng producer
ProducerHandle2=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4, &ProducerID2);
// Tạo 2 luồng tiêu thụ thi hành ngay
ConsumerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Consumer,0, 0, &ConsumerID1); //0: luồng tiêu thụ vận hành ngay, ko ngủ
ConsumerHandle2=CreateThread(0,0,
(LPTHREAD_START_ROUTINE)Consumer,
0, 0, &ConsumerID2);
while(1){
printf("\n- Nhap P/p de san xuat, 0 de ket thuc:”);
//P đánh thức nhà sx1, p sx2
switch (getch()){//biết người sử dụng bấm gì
case 'P':
ResumeThread(ProducerHandle1); //đánh thức luồng 1
break;
case 'p':
ResumeThread(ProducerHandle2);//đánh thức luồng 2
break;
case '0':
CloseHandle(ProducerHandle1);// hủy đối tượng(ở đây là luồng) có mục quản
CloseHandle(ProducerHandle2);
CloseHandle(ConsumerHandle1);
CloseHandle(ConsumerHandle2);
return 0;
}
Sleep(1);// ngủ 1 ms,(chờ in tăng lên 1) rồi mới showbuffer "Bước này không thực hiện thì kết quả sẽ bị sai".
ShowBuffer();
}
}[/quote]
MaiXuanSon (I22B)- Tổng số bài gửi : 49
Join date : 11/03/2013
Age : 38
Ưu và Khuyết Điểm Của Luồng
Ưu điểm là gì?
Thời gian chuyển đổi giữa các luồng ít hơn hẳn so với giữa các tiến trình vì không cần phải chuyển đổi không gian địa chỉ. Ngoài ra, vì chúng chia sẻ không gian địa chỉ nên các luồng trong một tiến trình có thể giao tiếp với nhau dễ dàng hơn nhiều.
Trên máy tính có nhiều bộ xử lý, chương trình dạng một tiến trình đơn chỉ chạy trên một CPU, còn chương trình dạng luồng có thể chia các luồng cho tất cả các bộ xử lý. Vì thế, nếu bạn chuyển chương trình dạng luồng sang máy chủ nhiều bộ xử lý thì nó sẽ chạy nhanh hơn.
Khuyết điểm?
Chương trình dạng luồng khó viết và kiểm lỗi hơn. Không phải mọi thư viện lập trình đều được thiết kế để dùng với luồng và không phải mọi ứng dụng cũ đều có thể làm việc tốt với ứng dụng dạng luồng. Một vài công cụ lập trình cũng làm cho việc thiết kế và thử nghiệm mã luồng khó khăn hơn.
Lỗi liên quan đến luồng cũng khó phát hiện hơn. Các luồng trong một quá trình có thể bị chồng chéo dữ liệu với nhau. Hệ điều hành có thể hạn chế số luồng thực thi chẳng hạn đọc và ghi dữ liệu cùng lúc. Việc định thời cho các luồng khác nhau để tránh xung đột là rất khó khăn.
Tuy nhiên, khi các ứng dụng dùng chung phức tạp và máy chủ nhiều bộ xử lý ngày càng phổ biến thì luồng sẽ ngày càng được dùng nhiều để thực hiện đa xử lý.
Thời gian chuyển đổi giữa các luồng ít hơn hẳn so với giữa các tiến trình vì không cần phải chuyển đổi không gian địa chỉ. Ngoài ra, vì chúng chia sẻ không gian địa chỉ nên các luồng trong một tiến trình có thể giao tiếp với nhau dễ dàng hơn nhiều.
Trên máy tính có nhiều bộ xử lý, chương trình dạng một tiến trình đơn chỉ chạy trên một CPU, còn chương trình dạng luồng có thể chia các luồng cho tất cả các bộ xử lý. Vì thế, nếu bạn chuyển chương trình dạng luồng sang máy chủ nhiều bộ xử lý thì nó sẽ chạy nhanh hơn.
Khuyết điểm?
Chương trình dạng luồng khó viết và kiểm lỗi hơn. Không phải mọi thư viện lập trình đều được thiết kế để dùng với luồng và không phải mọi ứng dụng cũ đều có thể làm việc tốt với ứng dụng dạng luồng. Một vài công cụ lập trình cũng làm cho việc thiết kế và thử nghiệm mã luồng khó khăn hơn.
Lỗi liên quan đến luồng cũng khó phát hiện hơn. Các luồng trong một quá trình có thể bị chồng chéo dữ liệu với nhau. Hệ điều hành có thể hạn chế số luồng thực thi chẳng hạn đọc và ghi dữ liệu cùng lúc. Việc định thời cho các luồng khác nhau để tránh xung đột là rất khó khăn.
Tuy nhiên, khi các ứng dụng dùng chung phức tạp và máy chủ nhiều bộ xử lý ngày càng phổ biến thì luồng sẽ ngày càng được dùng nhiều để thực hiện đa xử lý.
VoMinhDien(I22B)- Tổng số bài gửi : 34
Join date : 11/03/2013
Re: Thảo luận Bài 5
Mình có vài ví dụ khác, các bạn góp ý nha thêm nhaHongGiaPhu (I22A) đã viết:Trong tiến trình có thể có nhiều tiểu trình còn được gọi là luồng.
Luồng (Thread) còn được gọi là tiểu trình nhẹ (LWP - Light Weight Process) là một đơn vị cơ bản sử dụng CPU. Trong một tiến trình có nhiều tiến trình trong đó có một luồng chính và nhiều luồng phụ, các luồng này có thể chia sẻ các tài nguyên cho nhau và nhiều luồng có thể dùng chung một mã code.
Lợi ích của đa luồng:
1/ Khả năng đáp ứng, phản hồi (Responsiveness): Trong suốt quá trình vận hành, khi một luồng bị bận hoặc tắc nghẽn thì các luồng khác vẫn vận hành bình thường để thực hiện công việc của người dùng.
Vd: Các trực đài viên (các luồng) sẽ cùng nhau đáp ứng thắc mắc của khách hàng khi gọi tới cùng 1 tổng đài (trong 1 tiến trình cha).
2/ Chia sẻ tài nguyên (Resource Sharing): Do được sinh ra trong một tiến trình cha, các luồng có thể dùng chung bộ nhớ và tài nguyên với luồng cha.
Vd: Trong 1 gia đình (1 tiến trình), các thành viên trong một gia đình (các luồng bên trong) sẽ dùng chung các thiết bị (tài nguyên) như xem chung tivi, dùng chung máy giặt, tủ lạnh...
3/ Tiết kiệm (Economy): Do cùng khả năng chia sẻ và dùng chung tài nguyên của các luồng trong 1 tiến trình sẽ tiết kiệm tài nguyên hơn nhiều so với CPU cấp phát tài nguyên cho các tiến trình khác nhau.
Vd: Cùng với ví dụ trên, rõ ràng ta thấy việc các thành viên trong gia đình dùng chung các thiết bị như vậy sẽ tiết kiệm chi phí kinh tế hơn nhiều so với việc mỗi thành viên bỏ tiền túi ra và dùng riêng cho mỗi thiết bị.
4/ Tận dụng và khai thác tối ưu của kiến trúc đa xử lí: Nếu như một máy tính có nhiều CPU thì công nghệ đa luồng được khai thác rất hiệu quả khi một luồng có thể chạy trên CPU này trong khi luồng khác có thể dùng CPU khác để cùng song song làm việc => tốc độ công việc được cải thiện rõ rệt.
Vd: Trong một công ty, các nhân viên sẽ được trang bị một máy tính độc lập (một CPU) và cùng làm việc trong công ty mà sẽ nhanh hơn nhiều so với việc mỗi nhân viên chờ đến lượt mình sử dụng nếu công ty chỉ có một máy tính.
5/ Lập trình đa luồng sẽ dễ hơn nhiều so với lập trình đa tiến trình.
VD1 - Responsiveness
Các cô tổng đài 109 là các luồng. Khi khách hàng gọi điện thoại hỏi 108, thì một trong các cô ( cô thứ 1) sẽ trả lời. Nếu trong thời điểm đó khác hàng thứ hai gọi 108, thì một trong các cô ( cô thứ 2) còn lại sẽ trả lời cho khach hàng
VD2 - (Resource Sharing)
Trong nhà ta có kệ sách, ti vi, xe máy, mọi người trong nhà có thể dùng chung sách tivi, xe máy
VD3 - (Economy)
Các bạn trong lớp đang dùng chung 1 cái bảng, ai cần ghi thì ghi, ai cần thì chụp hình về xem.
VoMinhThang(I22B)- Tổng số bài gửi : 41
Join date : 11/03/2013
Khái niệm tiến trình (process) và luồng (thread)
Tiến trình (process) là trạng thái tức thời của một chương trình đang chạy trên máy tính. Nó bao gồm bộ nhớ cần thiết để chạy chương trình (không gian địa chỉ của quá trình) và khả năng kiểm soát hiện trạng của bộ xử lý trong quá trình thực thi chương trình (tiến trình điều khiển của quá trình)
Luồng (thread) tương tự như quá trình nhưng chỉ bao gồm tiến trình điều khiển. Nhiều luồng sử dụng không gian địa chỉ của một quá trình.
Quá trình và luồng có chung một mục đích: buộc máy tính phải làm nhiều việc hơn tại một thời điểm. Để làm điều đó, bộ xử lý (hay các bộ xử lý) phải chuyển đổi một cách trơn tru giữa các tác vụ, điều này đòi hỏi chương trình ứng dụng phải được thiết kế để chia sẻ tài nguyên máy tính.
Mỗi chương trình chạy trên một máy tính cần ít nhất là một quá trình. Quá trình đó bao gồm không gian địa chỉ (phần bộ nhớ máy tính mà ở đó chương trình chạy) và tiến trình điều khiển (cách thức để biết được phần nào của chương trình đang được bộ xử lý thực thi tại bất kỳ thời điểm nào). Nói cách khác, quá trình là một vùng làm việc và cách thức quản lý những gì chương trình đang thực hiện. Khi một số chương trình chạy cùng một thời điểm, mỗi chương trình sẽ có không gian địa chỉ và tiến trình điều khiển của riêng nó (xem sơ đồ).
Để phục vụ nhiều người dùng, một quá trình có thể cần phải phân nhánh, hay tạo bản sao của chính nó để tạo ra một quá trình con. Cũng giống như quá trình mẹ, quá trình con cũng có không gian địa chỉ và tiến trình điều khiển riêng. Tuy nhiên, thường thì khi quá trình mẹ chấm dứt, mọi quá trình con mà nó khởi động cũng sẽ tự động chấm dứt.
Hệ điều hành đa nhiệm như Unix hay Windows thực hiện việc chuyển đổi qua lại giữa các quá trình, lần lượt phân thời gian sử dụng CPU cho từng quá trình. Nếu máy tính có nhiều CPU, mỗi quá trình có thể được gán riêng cho một trong các CPU.
Điều này thích hợp với các chương trình đơn giản. Các ứng dụng phức tạp hiện nay như xử lý văn bản hay bảng tính có thể xem như là nhiều chương trình khác nhau với yêu cầu chuyển đổi qua lại và giao tiếp giữa các quá trình liên tục. Đây là một vấn đề vì phải mất thời gian để chuyển đổi giữa các quá trình.
CPU hiện đại có bộ quản lý bộ nhớ (memory management unit – MMU) để ngăn bất kỳ quá trình nào vi phạm không gian bộ nhớ của quá trình khác. Chuyển từ một quá trình này sang quá trình khác – được gọi là chuyển ngữ cảnh – có nghĩa là lập trình lại MMU để chỉ đến không gian địa chỉ khác cùng với việc lưu và phục hồi thông tin của một quá trình. Hệ điều hành chịu trách nhiệm quản lý chi tiết của việc chuyển ngữ cảnh nhưng nó cũng tiêu tốn thời gian của CPU. Do mỗi quá trình đều được cách ly với những quá trình khác, giao tiếp giữa các quá trình đòi hỏi phải có những chức năng đặc biệt. Tương tự việc chuyển ngữ cảnh, truyền thông giữa các quá trình cũng chiếm thời gian của bộ xử lý.
Tất cả thời gian trên sẽ cộng dồn lên khi nhiều chương trình chạy cùng lúc hay khi có nhiều người dùng mà mỗi người đều yêu cầu chạy nhiều quá trình cũng lúc. Càng nhiều quá trình chạy thì càng tốn nhiều thời gian của CPU và hệ điều hành để thực hiện công việc chuyển ngữ cảnh.
Nếu số quá trình đủ nhiều, máy chủ có thể phải dành toàn bộ thời gian để thực hiện việc chuyển đổi giữa các quá trình mà không thể thực sự xử lý được công việc nào.
Luồng (thread) tương tự như quá trình nhưng chỉ bao gồm tiến trình điều khiển. Nhiều luồng sử dụng không gian địa chỉ của một quá trình.
Quá trình và luồng có chung một mục đích: buộc máy tính phải làm nhiều việc hơn tại một thời điểm. Để làm điều đó, bộ xử lý (hay các bộ xử lý) phải chuyển đổi một cách trơn tru giữa các tác vụ, điều này đòi hỏi chương trình ứng dụng phải được thiết kế để chia sẻ tài nguyên máy tính.
Mỗi chương trình chạy trên một máy tính cần ít nhất là một quá trình. Quá trình đó bao gồm không gian địa chỉ (phần bộ nhớ máy tính mà ở đó chương trình chạy) và tiến trình điều khiển (cách thức để biết được phần nào của chương trình đang được bộ xử lý thực thi tại bất kỳ thời điểm nào). Nói cách khác, quá trình là một vùng làm việc và cách thức quản lý những gì chương trình đang thực hiện. Khi một số chương trình chạy cùng một thời điểm, mỗi chương trình sẽ có không gian địa chỉ và tiến trình điều khiển của riêng nó (xem sơ đồ).
Để phục vụ nhiều người dùng, một quá trình có thể cần phải phân nhánh, hay tạo bản sao của chính nó để tạo ra một quá trình con. Cũng giống như quá trình mẹ, quá trình con cũng có không gian địa chỉ và tiến trình điều khiển riêng. Tuy nhiên, thường thì khi quá trình mẹ chấm dứt, mọi quá trình con mà nó khởi động cũng sẽ tự động chấm dứt.
Hệ điều hành đa nhiệm như Unix hay Windows thực hiện việc chuyển đổi qua lại giữa các quá trình, lần lượt phân thời gian sử dụng CPU cho từng quá trình. Nếu máy tính có nhiều CPU, mỗi quá trình có thể được gán riêng cho một trong các CPU.
Điều này thích hợp với các chương trình đơn giản. Các ứng dụng phức tạp hiện nay như xử lý văn bản hay bảng tính có thể xem như là nhiều chương trình khác nhau với yêu cầu chuyển đổi qua lại và giao tiếp giữa các quá trình liên tục. Đây là một vấn đề vì phải mất thời gian để chuyển đổi giữa các quá trình.
CPU hiện đại có bộ quản lý bộ nhớ (memory management unit – MMU) để ngăn bất kỳ quá trình nào vi phạm không gian bộ nhớ của quá trình khác. Chuyển từ một quá trình này sang quá trình khác – được gọi là chuyển ngữ cảnh – có nghĩa là lập trình lại MMU để chỉ đến không gian địa chỉ khác cùng với việc lưu và phục hồi thông tin của một quá trình. Hệ điều hành chịu trách nhiệm quản lý chi tiết của việc chuyển ngữ cảnh nhưng nó cũng tiêu tốn thời gian của CPU. Do mỗi quá trình đều được cách ly với những quá trình khác, giao tiếp giữa các quá trình đòi hỏi phải có những chức năng đặc biệt. Tương tự việc chuyển ngữ cảnh, truyền thông giữa các quá trình cũng chiếm thời gian của bộ xử lý.
Tất cả thời gian trên sẽ cộng dồn lên khi nhiều chương trình chạy cùng lúc hay khi có nhiều người dùng mà mỗi người đều yêu cầu chạy nhiều quá trình cũng lúc. Càng nhiều quá trình chạy thì càng tốn nhiều thời gian của CPU và hệ điều hành để thực hiện công việc chuyển ngữ cảnh.
Nếu số quá trình đủ nhiều, máy chủ có thể phải dành toàn bộ thời gian để thực hiện việc chuyển đổi giữa các quá trình mà không thể thực sự xử lý được công việc nào.
TruongTranThanhTu(I22B)- Tổng số bài gửi : 34
Join date : 11/03/2013
Hyper Threading
Kỹ thuật siêu phân luồng (hyper threading) giúp CPU có khả năng chạy được nhiều ứng dụng cùng một lúc bằng cách chia thành các luồng xử lý khác nhau. Để có thể sử dụng các ứng dụng ở cùng một thời điểm
Hyper threading ( công nghệ siêu phân luồng) là công nghệ cho phép một CPU vật lý hoạt động trên hệ điều hành như là hai CPU và hệ điều hành không thể phân biệt được. Nhiệm vụ của hệ điều hành là gửi hai chuỗi lệnh tới hai CPU và phần cứng sẽ đảm nhiệm những công việc còn lại.kỹ thuật siêu phân luồng (hyper threading) giúp CPU có khả năng chạy được nhiều ứng dụng cùng một lúc bằng cách chia thành các luồng xử lý khác nhau. Để có thể sử dụng các ứng dụng ở cùng một thời điểm
Nguyên lý hoạt động: Về bản chất, một nhân xử lý không thể xử lý hai luồng thông tin vào cùng một thời điểm. Nếu chúng ta muốn cùng một lúc có được nhiều ứng dụng (hay thực chất là rất nhiều các process con, hoặc rất nhiều thread) chạy song song, hệ điều hành của chúng ta phải ra lệnh cho nhân xử lý liên tục và chuyển qua chuyển lại tác vụ xử lý cho từng thread. Quá trình này diễn ra rất-rất nhanh và hoàn toàn không thể nhận biết bằng mắt thường, tạo cảm giác như CPU của chúng ta xử lý tất cả các khối lượng công việc đó song song cùng một thời điểm
Hyper threading ( công nghệ siêu phân luồng) là công nghệ cho phép một CPU vật lý hoạt động trên hệ điều hành như là hai CPU và hệ điều hành không thể phân biệt được. Nhiệm vụ của hệ điều hành là gửi hai chuỗi lệnh tới hai CPU và phần cứng sẽ đảm nhiệm những công việc còn lại.kỹ thuật siêu phân luồng (hyper threading) giúp CPU có khả năng chạy được nhiều ứng dụng cùng một lúc bằng cách chia thành các luồng xử lý khác nhau. Để có thể sử dụng các ứng dụng ở cùng một thời điểm
Nguyên lý hoạt động: Về bản chất, một nhân xử lý không thể xử lý hai luồng thông tin vào cùng một thời điểm. Nếu chúng ta muốn cùng một lúc có được nhiều ứng dụng (hay thực chất là rất nhiều các process con, hoặc rất nhiều thread) chạy song song, hệ điều hành của chúng ta phải ra lệnh cho nhân xử lý liên tục và chuyển qua chuyển lại tác vụ xử lý cho từng thread. Quá trình này diễn ra rất-rất nhanh và hoàn toàn không thể nhận biết bằng mắt thường, tạo cảm giác như CPU của chúng ta xử lý tất cả các khối lượng công việc đó song song cùng một thời điểm
TruongTranThanhTu(I22B)- Tổng số bài gửi : 34
Join date : 11/03/2013
Lợi ích của đa luồng
-Khả năng đáp ứng (Responsiveness) tốt hơn: Trong khi một luồng bị ách hoặc quá bận, luồng khác vẫn vận hành bình thường (Luồng chính của trình duyệt vẫn tương tác với người dùng trong khi dữ liệu được lấy về).
- Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
- Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5 lần).
- Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng
- Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
- Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5 lần).
- Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng
NguyenVanPhat(I22B)- Tổng số bài gửi : 16
Join date : 13/03/2013
Nguyên lý của tập luồng
+ Tiến trình cha tạo lập sẵn 1 tập luồng khi khởi động.
+ Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
+ Khi tiến trình cha nhận thêm 1 yêu cầu, một luồng được đánh thức và đưa vào vận hành.
+ Phục vụ xong, luồng được đưa trả về tập luồng.
+ Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ cho đến khi luồng được giải phóng.
+ Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
+ Khi tiến trình cha nhận thêm 1 yêu cầu, một luồng được đánh thức và đưa vào vận hành.
+ Phục vụ xong, luồng được đưa trả về tập luồng.
+ Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ cho đến khi luồng được giải phóng.
NguyenVanPhat(I22B)- Tổng số bài gửi : 16
Join date : 13/03/2013
Các trạng thái của luồng
-Running : đang chạy – được hiểu là khi hệ thống định rõ vị trí luồng trong CPU
-Ready to run : đã chạy ( nhưng chưa được định vị trí trong CPU )
-Resumed : luồng ở trạng thái “ready to run” sau khi suspended/ blocked
-Suspended : luồng tự nguyện dừng lại để cho 1 luồng khác chạy
-Blocked : luồng đang đợi tài nguyên để tiếp tục hoặc bị 1 sự kiện của hệ thống
chặn ngang
-Ready to run : đã chạy ( nhưng chưa được định vị trí trong CPU )
-Resumed : luồng ở trạng thái “ready to run” sau khi suspended/ blocked
-Suspended : luồng tự nguyện dừng lại để cho 1 luồng khác chạy
-Blocked : luồng đang đợi tài nguyên để tiếp tục hoặc bị 1 sự kiện của hệ thống
chặn ngang
NguyenVanPhat(I22B)- Tổng số bài gửi : 16
Join date : 13/03/2013
Những lợi ích của công nghệ đa luồng
- Khả năng đáp ứng tốt hơn, khi 1 luồng bị treo hoặc quá bận thì luồng khác vẫn làm việc 1 cách bình thường (Luồng chính của người dùng vẫn tương tác tốt với người dùng trong khi vẫn lấy được dữ liệu về.
VD: Tổng đài 188 là 1 vd minh họa của đa luồng (1 cô nhân viên trực trả lời tổng đài khi 1 khách hàng gọi hỏi (7 kì quan trên thế giới là những kì quan nào…) Trong khi đó nhân viên đó đang bận nhưng tổng đài có rất nhiều cô nhân viên khác phục vụ (gọi là đa luồng), 1 cô phục vụ (gọi là đơn luồng), cô nhân viên đó đang bận vẫn có sự trả lời của cô khác cứ như thế làm việc gọi là đa luồng.
- Đa luồng chia sẽ tài nguyên dể dàng, mặc định các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồn vận hành cùng 1 địa chỉ do đó dể dùng chung tài nguyên hơn so với trường hợp đa tiến tình.
VD: Trong lớp học việc dùng chung 1 cái bảng dễ sửa dễ thay đổi, nếu thay đổi sẽ thay đổi tất cả.
- Đa luồng tiết kiệm hơn: Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồn chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn. Việc tạo mới 1 luồng sẽ dể hơn rất nhiều so với việc tạo mới 1 tiến tình mới.
VD: Trong 1 gia đình có anh chị sắp xây dựng 1 gia đình mới nếu như xây thêm 1 căn nhà (hoặc căn phòng) sẽ tốn kém và khó hơn rất nhiều so với việc ngăn 1 căn phòng trong 1 gia đình lớn thành nhiều ngăn (chia ra nhiều phòng sẽ nhanh hơn và tiết kiệm hơn rất nhiều so với tạo dựng mới, tiết kiệm hơn rất nhiều.
- Tận dụng được thế mạnh của kiến trúc đa xử lý : Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng. Việc chuyển từ luồng này sang luồng kia là rất nhanh.
- Lập trình đa luồng dể hơn là lập trình đa tiến trình.
VD: Tổng đài 188 là 1 vd minh họa của đa luồng (1 cô nhân viên trực trả lời tổng đài khi 1 khách hàng gọi hỏi (7 kì quan trên thế giới là những kì quan nào…) Trong khi đó nhân viên đó đang bận nhưng tổng đài có rất nhiều cô nhân viên khác phục vụ (gọi là đa luồng), 1 cô phục vụ (gọi là đơn luồng), cô nhân viên đó đang bận vẫn có sự trả lời của cô khác cứ như thế làm việc gọi là đa luồng.
- Đa luồng chia sẽ tài nguyên dể dàng, mặc định các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồn vận hành cùng 1 địa chỉ do đó dể dùng chung tài nguyên hơn so với trường hợp đa tiến tình.
VD: Trong lớp học việc dùng chung 1 cái bảng dễ sửa dễ thay đổi, nếu thay đổi sẽ thay đổi tất cả.
- Đa luồng tiết kiệm hơn: Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồn chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn. Việc tạo mới 1 luồng sẽ dể hơn rất nhiều so với việc tạo mới 1 tiến tình mới.
VD: Trong 1 gia đình có anh chị sắp xây dựng 1 gia đình mới nếu như xây thêm 1 căn nhà (hoặc căn phòng) sẽ tốn kém và khó hơn rất nhiều so với việc ngăn 1 căn phòng trong 1 gia đình lớn thành nhiều ngăn (chia ra nhiều phòng sẽ nhanh hơn và tiết kiệm hơn rất nhiều so với tạo dựng mới, tiết kiệm hơn rất nhiều.
- Tận dụng được thế mạnh của kiến trúc đa xử lý : Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng. Việc chuyển từ luồng này sang luồng kia là rất nhanh.
- Lập trình đa luồng dể hơn là lập trình đa tiến trình.
dangvannhan(I22A)- Tổng số bài gửi : 29
Join date : 11/03/2013
Re: Thảo Luận Bài 5
Trình bày nguyên lý tập luồng (thread pools) ví dụ minh họa:
- Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
- Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
- Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
- Phục vụ xong, luồng được đưa trả về tập luồng.
- Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
Ví dụ:
ví dụ 1: Năm 1999 thầy đi đến Mạng Phương Nam: Mạng Phương Nam là áp dụng công nghệ CGI(COMMON GATEWAY INTERFACE)(ĐA TIẾN TRÌNH) cho nhu cầu tìm kiếm việc làm qua mạng. khi đó Mạng Phương Nam gặp sự cố , khi có nhiều người gửi yêu cầu cùng một lúc thì server treo phải reset lại server cho nạp lại vì công nghệ CGI sử dụng Heavy Weight Process. khi đó thầy đưa ra phương án giải quyết cho sự cố trên là áp dụng công nghệ ASP(ACTIVE SERVER PAGES)(ĐA LUỒNG) VÀ đã giải quyết được sự cố và giúp Mạng Phương Nam nâng cao hơn về tính năng quản lý và giao diện web.
Ví dụ 2:
Trong một doanh trại quân đội sẽ có một tướng lĩnh (tiến trình cha) và sẽ có một đội binh (tập luồng).
Đội binh này sẽ sẳn sàng chiến đầu khi có mệnh lệnh (sẵn sàng chờ công việc).
Khi có một tên địch đột nhập, Tướng lĩnh sẽ điều binh sĩ 1 (một luồng) đi bắt tên địch (một luồng được đánh thức và đưa vào vận hành).
Trong khi đó, lại có thêm một tên địch khác đột nhập (nhận thêm một yêu cầu), Tướng lĩnh sẽ điều binh sĩ 2 (một luồng) đi bắt địch (một luồng khác được đánh thức và đưa vào vận hành).
Sau khi bắt địch xong, binh sĩ sẽ trở về doanh trại (luồng được trả về tập luồng)
- Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
- Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
- Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
- Phục vụ xong, luồng được đưa trả về tập luồng.
- Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
Ví dụ:
ví dụ 1: Năm 1999 thầy đi đến Mạng Phương Nam: Mạng Phương Nam là áp dụng công nghệ CGI(COMMON GATEWAY INTERFACE)(ĐA TIẾN TRÌNH) cho nhu cầu tìm kiếm việc làm qua mạng. khi đó Mạng Phương Nam gặp sự cố , khi có nhiều người gửi yêu cầu cùng một lúc thì server treo phải reset lại server cho nạp lại vì công nghệ CGI sử dụng Heavy Weight Process. khi đó thầy đưa ra phương án giải quyết cho sự cố trên là áp dụng công nghệ ASP(ACTIVE SERVER PAGES)(ĐA LUỒNG) VÀ đã giải quyết được sự cố và giúp Mạng Phương Nam nâng cao hơn về tính năng quản lý và giao diện web.
Ví dụ 2:
Trong một doanh trại quân đội sẽ có một tướng lĩnh (tiến trình cha) và sẽ có một đội binh (tập luồng).
Đội binh này sẽ sẳn sàng chiến đầu khi có mệnh lệnh (sẵn sàng chờ công việc).
Khi có một tên địch đột nhập, Tướng lĩnh sẽ điều binh sĩ 1 (một luồng) đi bắt tên địch (một luồng được đánh thức và đưa vào vận hành).
Trong khi đó, lại có thêm một tên địch khác đột nhập (nhận thêm một yêu cầu), Tướng lĩnh sẽ điều binh sĩ 2 (một luồng) đi bắt địch (một luồng khác được đánh thức và đưa vào vận hành).
Sau khi bắt địch xong, binh sĩ sẽ trở về doanh trại (luồng được trả về tập luồng)
NguyenVanTu(I22A)- Tổng số bài gửi : 23
Join date : 12/03/2013
Khái niệm Luồng và so sánh với tiến trình
Một luồng thường được gọi là tiến trình nhẹ (lightweight proces-LWP), là một đơn vị cơ bản của việc sử dụng CPU; nó hình thành gồm: một định danh luồng (thread ID), một bộ đếm chương trình, tập thanh ghi và ngăn xếp. Nó chia sẻ với các luồng khác thuộc cùng một tiến trình phần mã, phần dữ liệu, và tài nguyên hệ điều hành như các tập tin đang mở và các tín hiệu.
Một tiến trình truyền thống (hay tiến trình nặng) có một luồng điều khiển đơn. Nếu tiến trình có nhiều luồng điều khiển, nó có thể thực hiện nhiều hơn một tác vụ tại một thời điểm.
Sự giống nhau:
- Đều có thông tin trạng thái
- Luồng cũng là tiến trình nhưng là tiến trình nhẹ (Light Weigh Process)
- Đa luồng hay đa tiến trình có thể liên quan đến một chương trình.
- Chia sẻ tài nguyên cho nhau, tăng tốc tính toán, đảm bảo tính đơn thể
- Do luồng cùng vận hành trong 1 vùng địa chỉ, vì vậy dễ dùng chung tài nguyên hơn đa tiến trình
Ví dụ: Mình cần mượn xe đi đâu đó thì mượn xe trong gia đình để đi thì dễ hơn mượn của người ngoài
- Do luồng chung tài nguyên với luồng cha nên việc tạo lập và chuyển đổi ngữ cảnh cũng nhanh hơn tiến trình
Ví dụ: Việc ngăn phòng riêng ra trong nhà thì dễ hơn việc xây thêm hay mua thêm một nhà khác.
- Cấp phát tài nguyên bộ nhớ cho tiến trình khá tốn kém.
- Lập trình đa luồng thì dễ hơn lập trình đa tiến trình.
Sự khác nhau:
- Lập trình đa luồng dễ hơn lập trình đa tiến trình.
- Tạo mới một tiến trình khó hơn tạo mới một luồng.
- Luồng không cần gởi, nhận thông điệp.
- Luồng chuyển đổi ngữ cảnh nhanh và ít chiếm tài nguyên hơn tiến trình.
- Luồng chia sẻ tài nguyên dùng chung dể hơn tiến trình.
Một tiến trình truyền thống (hay tiến trình nặng) có một luồng điều khiển đơn. Nếu tiến trình có nhiều luồng điều khiển, nó có thể thực hiện nhiều hơn một tác vụ tại một thời điểm.
Sự giống nhau:
- Đều có thông tin trạng thái
- Luồng cũng là tiến trình nhưng là tiến trình nhẹ (Light Weigh Process)
- Đa luồng hay đa tiến trình có thể liên quan đến một chương trình.
- Chia sẻ tài nguyên cho nhau, tăng tốc tính toán, đảm bảo tính đơn thể
- Do luồng cùng vận hành trong 1 vùng địa chỉ, vì vậy dễ dùng chung tài nguyên hơn đa tiến trình
Ví dụ: Mình cần mượn xe đi đâu đó thì mượn xe trong gia đình để đi thì dễ hơn mượn của người ngoài
- Do luồng chung tài nguyên với luồng cha nên việc tạo lập và chuyển đổi ngữ cảnh cũng nhanh hơn tiến trình
Ví dụ: Việc ngăn phòng riêng ra trong nhà thì dễ hơn việc xây thêm hay mua thêm một nhà khác.
- Cấp phát tài nguyên bộ nhớ cho tiến trình khá tốn kém.
- Lập trình đa luồng thì dễ hơn lập trình đa tiến trình.
Sự khác nhau:
- Lập trình đa luồng dễ hơn lập trình đa tiến trình.
- Tạo mới một tiến trình khó hơn tạo mới một luồng.
- Luồng không cần gởi, nhận thông điệp.
- Luồng chuyển đổi ngữ cảnh nhanh và ít chiếm tài nguyên hơn tiến trình.
- Luồng chia sẻ tài nguyên dùng chung dể hơn tiến trình.
NguyenVanTu(I22A)- Tổng số bài gửi : 23
Join date : 12/03/2013
Re: Thảo luận Bài 5
Giải thích chi tiết . ^^nguyenthithutrang (I11C) đã viết:NguyenQuocHuy (I22B) đã viết:#include < stdio . h >
#include < conio . h >
#include < windows . h > // Sử dụng được hàm win32 API
#define BUFFER_SIZE 10 // định nghĩa một buffer có 10 khoang chứa
int buffer[BUFFER_SIZE];
int in=0; // giá trị vị trí xếp sản phẩm vào
int out=0;// giá trị vị trí lấy sản phẩm ra
int nextProduced=1;// biến trung gian, chứa số hiệu sản phẩm đầu tiên
void Producer(){ // nhà sản xuất
while (1){
// ... Sản xuất (nextProduced)
while(((in+1)%BUFFER_SIZE)==out);// khoang chứa đầy thì quẩn tại đây đến khi nào có chỗ trống
buffer[in]=nextProduced++; // cho sản phẩm vào mảng tại vị trí in
in=(in+1)%BUFFER_SIZE; //sau khi chèn, tăng in lên 1, nếu in đang nằm ở vị trí cuối mảng sẽ nhảy về đầu mảng
SuspendThread(GetCurrentThread()); //getcureentthread: hàm của thư viện win32 API, trả về giá trị mục quản của luồng hiện hành, vd: 1700. SuspendThread(): ngừng luồng có mục quản là giá trị trong ngoặc, vd: SuspendThread(1700) ngừng luồng có mục quản 1700
}
}
void Consumer(){ // nhà tiêu thụ
int nextConsumed; // biến chứa sản phẩm được tiêu thụ
while (1){
while(in==out); //trong khoang chứa hết sản phẩm thì quẩn tại đây cho đến khi nào trong buffer có sản phẩm
nextConsumed=buffer[out]; //sản phẩm ở vị trí out được đưa vào biến netxconsumed
out=(out+1)%BUFFER_SIZE;//out tăng lên 1, nếu out đang nằm ở cuối mảng thì nhảy lên đầu mảng
// ... Tiêu thụ (nextConsumed)
Sleep(GetTickCount()%5000); // hàm gettickcount() sẽ trả về thời gian tính bằng ms trôi qua kể từ khi hệ thống khởi động tới thời điểm hiện tại, kết quả sẽ ra được con số rất lớn và chia lấy số dư cho 5000 sẽ được 1 con số từ 0-4999, cho luồng tiêu thụ này ngủ trong khoảng thời gian đó.
}
}
void ShowBuffer(){ // In nội dung Buffer
const char * LeftMargin="\n\t";
int i;
printf(LeftMargin);
for(i=0; i<(in*5);i++) putchar(' '); printf("!in");
printf(LeftMargin);
for (i=0; iprintf("S%2d, ",buffer[i]);
printf("S%2d",buffer[BUFFER_SIZE-1]);
printf(LeftMargin);
for(i=0; i<(out*5); i++) putchar(' ');printf("^out");
printf("\n");
}
int main(){
HANDLE ProducerHandle1, ProducerHandle2; // lưu mục quản của 2 nhà sx vào 2 biến ProducerHandle1, ProducerHandle2
HANDLE ConsumerHandle1, ConsumerHandle2; //lưu mục quản của 2 nhà tiêu thụ
DWORD ProducerID1, ProducerID2; // mã số định danh của luồng sản xuất
DWORD ConsumerID1, ConsumerID2; // mã số định danh của luồng tiêu thụ
// tạo 2 luồng sản xuất trong trạng thái ngủ
ProducerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4,&ProducerID1);// các đối số đầu ko quan tâm vì có mới chạy được
// số 4 chỉ ra luồng vừa tạo sẽ không chạy mà ngủ luôn, &ProducerID1 chỉ ra luồng sẽ có mã số định danh là ProducerID1
// sau khi làm lệnh này, sẽ có 2 luồng, luồng ctrinh này và luồng producer
ProducerHandle2=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Producer,0, 4, &ProducerID2);
// Tạo 2 luồng tiêu thụ thi hành ngay
ConsumerHandle1=CreateThread(0,0,(LPTHREAD_START_ROUTINE)Consumer,0, 0, &ConsumerID1); //0: luồng tiêu thụ vận hành ngay, ko ngủ
ConsumerHandle2=CreateThread(0,0,
(LPTHREAD_START_ROUTINE)Consumer,
0, 0, &ConsumerID2);
while(1){
printf("\n- Nhap P/p de san xuat, 0 de ket thuc:”);
//P đánh thức nhà sx1, p sx2
switch (getch()){//biết người sử dụng bấm gì
case 'P':
ResumeThread(ProducerHandle1); //đánh thức luồng 1
break;
case 'p':
ResumeThread(ProducerHandle2);//đánh thức luồng 2
break;
case '0':
CloseHandle(ProducerHandle1);// hủy đối tượng(ở đây là luồng) có mục quản
CloseHandle(ProducerHandle2);
CloseHandle(ConsumerHandle1);
CloseHandle(ConsumerHandle2);
return 0;
}
Sleep(1);// ngủ 1 ms,(chờ in tăng lên 1) rồi mới showbuffer !
ShowBuffer();
}
}
Giải thích 1 số hàm trong bài toán sản xuất tiêu thụ
Hàm GetCurrentThread: dùng để lấy về mục quản của luồng sản xuất hiện hành(mục quản: là con số do hệ điều hành cấp ho luồng hiện hành)
Hàm SuspendThread: dùng để tạm ngưng công việc của hàm với mục quản cho trước
Hàm Sleep: dùng để ngủ 1 số ms cho trước,hết khoảng thời gian đó nhà tiêu thụ lại làm việc tiếp
Hàm GetTickCount(): dùng để lấy số miligiay trôi qua kể từ khi hệ điều hành khởi động cho đến thời điểm gọi hàm này
HÀm ResumeThread: dùng để tiếp tục công việc của luồng với mục quản cho trước
Hàm CloseHandle: dùng để hủy đối tượng cho trước với mục quản cho trước. vd: CLoseHandle (10) :luồng 10 không làm việc nữa,bị đóng lại
NgoVanTuyen(I22B)- Tổng số bài gửi : 32
Join date : 22/02/2013
Những lợi ích của công nghệ đa luồng
Khả năng đáp ứng (Responsiveness) tốt hơn: Trong khi một luồng bị ách hoặc quá bận, luồng khác vẫn vận hành bình thường (Luồng chính của trình duyệt vẫn tương tác với người dùng trong khi dữ liệu được lấy về).
Ví dụ: Các cô ở tổng đài 108 là các luồng. Khi khách hàng điện thoại hỏi 108. Nếu chỉ có 1 cô phải trực 10 máy điện thoại thì khi chỉ có 1 cuộc điện thoại gọi đến thì cô sẽ trả lời tốt nhưng khi có khoảng 3 cuộc điện thoại trở lên thì cô không thể trả lời được kịp hết.
Nếu có nhiều cô cùng trực điện thoại thì lúc đó sẽ tốt hơn, đáp ứng được nhu cầu của khách hàng khi họ gọi đến .
Nếu trong thời điểm đó khách hàng thứ hai gọi 108, thì một trong các cô (cô thứ 2) còn lại sẽ trả lời cho khách hàng.
Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ: Trong nhà ta có kệ sách, tivi, xe gắn máy, ... mọi người trong nhà có thể dùng chung sách, tivi, xe máy.
Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5 lần).
Ví dụ: Các bạn trong lớp là các luồng đang dùng chung một cái bảng, ai cần ghi thi ghi, ai cần thì chụp hình về xem
Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng.
Ví dụ: Các cô ở tổng đài 108 là các luồng. Khi khách hàng điện thoại hỏi 108. Nếu chỉ có 1 cô phải trực 10 máy điện thoại thì khi chỉ có 1 cuộc điện thoại gọi đến thì cô sẽ trả lời tốt nhưng khi có khoảng 3 cuộc điện thoại trở lên thì cô không thể trả lời được kịp hết.
Nếu có nhiều cô cùng trực điện thoại thì lúc đó sẽ tốt hơn, đáp ứng được nhu cầu của khách hàng khi họ gọi đến .
Nếu trong thời điểm đó khách hàng thứ hai gọi 108, thì một trong các cô (cô thứ 2) còn lại sẽ trả lời cho khách hàng.
Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ: Trong nhà ta có kệ sách, tivi, xe gắn máy, ... mọi người trong nhà có thể dùng chung sách, tivi, xe máy.
Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém. Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5 lần).
Ví dụ: Các bạn trong lớp là các luồng đang dùng chung một cái bảng, ai cần ghi thi ghi, ai cần thì chụp hình về xem
Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng.
NguyenVanTu(I22A)- Tổng số bài gửi : 23
Join date : 12/03/2013
Phân biệt khái niệm luồng với tiến trình
-Luồng: là tiến trình nhẹ (LWP - Light Weight Process), một đơn vị cơ bản sử dụng CPU.
Luồng cũng có thông tin trạng thái như của tiến trình hệ thống (HWP - Heavy Weight
Process)
Ví dụ: Lớp học là một tiến trình. Trong lớp sẽ có một giáo viên(Luồng chính) và các học
viên (luồng phụ)
-Tiến trình: là chương trình trong thời gian thực hiện (đặt dưới sự quản lý của hệ điều
hành). Có sự phân biệt Tiến trình hệ thống (của Hệ điều hành) với Tiến trình người dùng.
Ví dụ: Lớp I12A đang học là một tiến trình đang hoạt động
Những ích lợi của công nghệ đa luồng
- Khả năng đáp ứng (Responsiveness) tốt hơn: Trong khi một luồng bị ách hoặc quá bận,
luồng khác vẫn vận hành bình thường (Luồng chính của trình duyệt vẫn tương tác với
người dùng trong khi dữ liệu được lấy về).
Ví dụ: Các cô ở tổng đài 108 là các luồng. Khi khách hàng điện thoại hỏi 108, thì một
trong các cô (cô thứ 1) sẽ trả lời. Nếu trong thời điểm đó khách hàng thứ hai gọi 108, thì
một trong các cô (cô thứ 2) còn lại sẽ trả lời cho khách hàng.
- Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ
nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ
dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ: Trong nhà ta có kệ sách, tivi, xe gắn máy, ... mọi người trong nhà có thể dùng
chung sách, tivi, xe máy.
-Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém.
Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh
cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5
lần).
Ví dụ: Các bạn trong lớp là các luồng đang dùng chung một cái bảng, ai cần ghi thi ghi,
ai cần thì chụp hình về xem
-Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ
máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng.
- Lập trình đa luồng dễ hơn lập trình đa tiến trình
vd: viết hàm tạo mới tiến trình khó hơn tạo luồng mới nhiều
Luồng cũng có thông tin trạng thái như của tiến trình hệ thống (HWP - Heavy Weight
Process)
Ví dụ: Lớp học là một tiến trình. Trong lớp sẽ có một giáo viên(Luồng chính) và các học
viên (luồng phụ)
-Tiến trình: là chương trình trong thời gian thực hiện (đặt dưới sự quản lý của hệ điều
hành). Có sự phân biệt Tiến trình hệ thống (của Hệ điều hành) với Tiến trình người dùng.
Ví dụ: Lớp I12A đang học là một tiến trình đang hoạt động
Những ích lợi của công nghệ đa luồng
- Khả năng đáp ứng (Responsiveness) tốt hơn: Trong khi một luồng bị ách hoặc quá bận,
luồng khác vẫn vận hành bình thường (Luồng chính của trình duyệt vẫn tương tác với
người dùng trong khi dữ liệu được lấy về).
Ví dụ: Các cô ở tổng đài 108 là các luồng. Khi khách hàng điện thoại hỏi 108, thì một
trong các cô (cô thứ 1) sẽ trả lời. Nếu trong thời điểm đó khách hàng thứ hai gọi 108, thì
một trong các cô (cô thứ 2) còn lại sẽ trả lời cho khách hàng.
- Chia sẻ tài nguyên (Resource Sharing): Theo mặc định, các luồng có thể dùng chung bộ
nhớ và tài nguyên của luồng cha. Vài luồng cùng vận hành trong 1 vùng địa chỉ, do đó dễ
dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ: Trong nhà ta có kệ sách, tivi, xe gắn máy, ... mọi người trong nhà có thể dùng
chung sách, tivi, xe máy.
-Tiết kiệm (Economy): Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc tốn kém.
Do luồng chung tài nguyên với cha và các luồng khác, việc tạo lập và chuyển ngữ cảnh
cũng nhanh hơn (Solaris 2: Tạo tiến trình chậm hơn 30 lần, Chuyển ngữ cảnh chậm hơn 5
lần).
Ví dụ: Các bạn trong lớp là các luồng đang dùng chung một cái bảng, ai cần ghi thi ghi,
ai cần thì chụp hình về xem
-Tận dụng được thế mạnh của kiến trúc đa xử lý: Đa luồng làm tăng tính song song trên hệ
máy nhiều CPU. Mỗi luồng có thể chạy bởi CPU riêng.
- Lập trình đa luồng dễ hơn lập trình đa tiến trình
vd: viết hàm tạo mới tiến trình khó hơn tạo luồng mới nhiều
Dao Duy Thanh(I22B)- Tổng số bài gửi : 16
Join date : 13/03/2013
Age : 34
Trình bày nguyên lý tập luồng
Tập luồng (Thread Pools):
-Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
-Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
-Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
-Phục vụ xong, luồng được đưa trả về tập luồng.
-Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
-Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
-Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
-Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
-Phục vụ xong, luồng được đưa trả về tập luồng.
-Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
NguyenBacHoi(I22B)- Tổng số bài gửi : 8
Join date : 13/03/2013
Tập luồng và vd!
1. Tập luồng (Thread Pools):
• Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
• Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
• Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
• Phục vụ xong, luồng được đưa trả về tập luồng.
• Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
2. Ví dụ:
Trong một doanh trai quân đội sẽ có một tướng lĩnh (tiến trình cha) và sẽ có một đội binh (tập luồng).
Đội binh này sẽ sẳn sàng chiến đầu khi có mệnh lệnh (sẵn sàng chờ công việc).
Khi có một tên địch đột nhập, Tướng lĩnh sẽ điều binh sĩ 1 (một luồng) đi bắt tên địch (một luồng được đánh thức và đưa vào vận hành).
Trong khi đó, lại có thêm một tên địch khác đột nhập (nhận thêm một yêu cầu), Tướng lĩnh sẽ điều binh sĩ 2 (một luồng) đi bắt địch (một luồng khác được đánh thức và đưa vào vận hành).
Sau khi bắt địch xong, binh sĩ sẽ trở về doanh trại (luồng được trả về tập luồng)
• Tiến trình cha tạo lập sẵn một tập luồng khi khởi động.
• Các luồng trong tập luồng luôn sẵn sàng chờ công việc.
• Khi tiến trình cha (ví dụ Web Server) nhận thêm một yêu cầu, một luồng được đánh thức và đưa vào vận hành.
• Phục vụ xong, luồng được đưa trả về tập luồng.
• Nếu số yêu cầu lớn hơn số luồng trong tập, tiến trình cha chờ đến khi có luồng được giải phóng.
2. Ví dụ:
Trong một doanh trai quân đội sẽ có một tướng lĩnh (tiến trình cha) và sẽ có một đội binh (tập luồng).
Đội binh này sẽ sẳn sàng chiến đầu khi có mệnh lệnh (sẵn sàng chờ công việc).
Khi có một tên địch đột nhập, Tướng lĩnh sẽ điều binh sĩ 1 (một luồng) đi bắt tên địch (một luồng được đánh thức và đưa vào vận hành).
Trong khi đó, lại có thêm một tên địch khác đột nhập (nhận thêm một yêu cầu), Tướng lĩnh sẽ điều binh sĩ 2 (một luồng) đi bắt địch (một luồng khác được đánh thức và đưa vào vận hành).
Sau khi bắt địch xong, binh sĩ sẽ trở về doanh trại (luồng được trả về tập luồng)
NgoVanTuyen(I22B)- Tổng số bài gửi : 32
Join date : 22/02/2013
Re: Thảo luận Bài 5
Mình muốn viết thêm một ví dụ về luồng và tiến trình :
Tiến trình như 1 hệ điều hành ví dụ như win7
Và luồng là tập hợp tất cả các chương trình cài đặt trong win 7
Khi cần xài thì ta cứ gọi chương trình ra
Tiến trình như 1 hệ điều hành ví dụ như win7
Và luồng là tập hợp tất cả các chương trình cài đặt trong win 7
Khi cần xài thì ta cứ gọi chương trình ra
HuynhHuuTai(I22A)- Tổng số bài gửi : 31
Join date : 12/03/2013
Re: Thảo luận Bài 5
Ví dụ về đa luồng
đa luồng thường dành cho cpu, ví dụ giải bài 1+1+2+2 thì 1 luồng nó sẽ phải làm 3 phép cộng theo thứ tự, làm xong phép cộng trước rồi mới làm phép cộng sau, đa luồng nó sẽ xử lý (1+1) đồng thời với (2+2), thời gian thực hiện chỉ bằng 2 phép cộng.
Song song thường dùng cho video card hơn, mỗi video card cao cấp có chừng 3000 shader giống như 3000 cái core cpu con, thích hợp với chẻ nhỏ công việc. Trong khi đó cpu đa luồng có thể làm trước các bước tiếp theo, còn videocard chỉ đơn giản là chia việc ra, mỗi core làm từ đầu đến cuối
đa luồng thường dành cho cpu, ví dụ giải bài 1+1+2+2 thì 1 luồng nó sẽ phải làm 3 phép cộng theo thứ tự, làm xong phép cộng trước rồi mới làm phép cộng sau, đa luồng nó sẽ xử lý (1+1) đồng thời với (2+2), thời gian thực hiện chỉ bằng 2 phép cộng.
Song song thường dùng cho video card hơn, mỗi video card cao cấp có chừng 3000 shader giống như 3000 cái core cpu con, thích hợp với chẻ nhỏ công việc. Trong khi đó cpu đa luồng có thể làm trước các bước tiếp theo, còn videocard chỉ đơn giản là chia việc ra, mỗi core làm từ đầu đến cuối
HuynhHuuTai(I22A)- Tổng số bài gửi : 31
Join date : 12/03/2013
Ví dụ về đa luồng.
Chủ nhà (luồng 1) đang tiếp khách (người dùng) trong phòng khách thì không phải lo là hộp thư trước cửa nhà có thư hay không, vì đã có người giúp việc (luồng thứ 2) lo nhiệm vụ nhận thư.
NguyenPhuongNhu(I22B)- Tổng số bài gửi : 36
Join date : 25/03/2013
Age : 40
So sánh đa luồng và đa tiến trình , những lợi ích của công nghệ đa luồng
So sánh đa luồng với đa tiến trình:
1. Giống nhau:
- Điều có thông tin trạng thái
- Luồng còn được gọi là tiến trình nhẹ.
- Nhiều luồng hoặc nhiều tiến trình có thể liên quan đến 1 chương trình.
- Dùng chung tài nguyên từ tiến trình(hoạc luồng) cha.
- Cùng có chức năng xử lý song song.
- Chia sẻ tài nguyên cho nhau.
- Tăng tốc tính toán.
- Đảm bảo tính đơn thể.
2. Khác nhau:
- Do các luồng cùng vận hành trong cùng 1 địa chỉ vì vậy dễ dùng chung tài nguyên hơn đa tiến trình
- Do các luồng chung tài nguyên với cha và các luồng khác nên việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn và ít chiếm tài nguyên hơn tiến trình.
- Cấp phát bộ nhớ và tài nguyên cho tiến trình thì tốn kém hơn luồng.
- Lập trình đa luồng thì dễ hơn lập trình đa tiến trình. Bởi vì trao đổi dữ liệu của lập trình đa luồng dễ hơn việc trao dữ liệu của lập trình đa tiến trình
- Đa tiến trình tốn resources hơn đa luồng.
Những lợi ích của công nghệ đa luồng :
- Đảm bảo được khả năng đáp ứng của tiến trình tốt hơn, khi lập trình đa luồng thì một khi 1 luồng có sự cố thì luồng khác vẫn làm việc, vẫn phản hồi ,trong trường hợp lập trình đơn luồng khi gặp sự cố thì luồng đó sẽ chậm và làm chậm luôn cả tiến trình, đa luồng một ứng dụng giao tiếp cho phép một chương trình tiếp tục chạy thậm chí nếu một phần của nó bị khóa hay đang thực hiện một thao tác dài, do đó gai tăng sự đáp ứng đối với người dùng,
Ví dụ : một trình duyệt web vẫn có thể đáp ứng người dùng bằng một luồng trong khi vẫn nạp bằng một luồng khác.
Ví dụ : Các cô ở tổng đài 108 là các luồng , khi khách hàng điện thoại hỏi 108, thì một trong các cô (người thứ nhất) sẽ trả lời, nếu trong thời điểm đó khách hàng thứ hai gọi 108,thì một trong các cô (cô thứ 2) còn lại sẽ trả lời
- Theo mặc định các luồng có thể dùng chung bộ nhớ và tai nguyên của luồng cha. Thuận lợi của việc chia sẻ mã là nó cho phép một ứng dụng có nhiều hoạt động của các luồng khác nằm trong cùng không gian, địa chỉ,vài luồng cùng vận hành trong một vùng địa chỉ dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ : trong nhà có kệ sách, xe máy, máy vi tính … mọi người có thể dùng chung và sử dụng chung kệ sách, xe máy, máy vi tính. Trong khi không thể dùng chung những đồ dùng trên với nhà khác được
Trong lớp chúng ta có thể dùng bảng củ lớp mình, chúng ta có thể chia sẻ các thông tin cần thiết cho tất cả các thành viên ở trong lớp biết,trong khi chúng ta khong thể dùng chung bảng của lớp khác để chia sẻ thông tin cho lớp mình được.
- Tiết kiệm (Economy) : Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc rất tốn kém. Do luồng có thể dùng chung tài nguyên với luồng cha và các luồng khác, việc tạo lập ngữ cảnh cũng nhanh hơn
Ví dụ : Các bạn trong lớp là các luồng đang dùng chung một cái bảng của lớp, ai cần ghi thì ghi, ai cần thì chụp hình về xem
Có thể bố trí một chỗ ngồi ở trong lớp cho một bạn đến sau dễ dàng hơn việc làm một chiếc ghế khác cho bạn đó.
- Chuyển ngữ cảnh từ luồng này sang luồng khác thì nhanh hơn chuyển ngữ cảnh từ tiến trình này sang tiến trình khác.
- Tận dụng được ưu thế kiến trúc đa xử lý (nhiều CPU). Khi đa luồng thì 1 luồng dùng CPU này và 1 luồng dùng CPU khác sẽ nhanh hơn và các luồng có thể làm việc song song , mỗi luồng có thể chạy bởi CPU riêng. Tiến trình đa luồng sẽ làm việc nhanh hơn tiến trình đơn luồng.
- Lập trình đa luồng dễ dàng hơn lập trình đa tiến trình .
1. Giống nhau:
- Điều có thông tin trạng thái
- Luồng còn được gọi là tiến trình nhẹ.
- Nhiều luồng hoặc nhiều tiến trình có thể liên quan đến 1 chương trình.
- Dùng chung tài nguyên từ tiến trình(hoạc luồng) cha.
- Cùng có chức năng xử lý song song.
- Chia sẻ tài nguyên cho nhau.
- Tăng tốc tính toán.
- Đảm bảo tính đơn thể.
2. Khác nhau:
- Do các luồng cùng vận hành trong cùng 1 địa chỉ vì vậy dễ dùng chung tài nguyên hơn đa tiến trình
- Do các luồng chung tài nguyên với cha và các luồng khác nên việc tạo lập và chuyển ngữ cảnh cũng nhanh hơn và ít chiếm tài nguyên hơn tiến trình.
- Cấp phát bộ nhớ và tài nguyên cho tiến trình thì tốn kém hơn luồng.
- Lập trình đa luồng thì dễ hơn lập trình đa tiến trình. Bởi vì trao đổi dữ liệu của lập trình đa luồng dễ hơn việc trao dữ liệu của lập trình đa tiến trình
- Đa tiến trình tốn resources hơn đa luồng.
Những lợi ích của công nghệ đa luồng :
- Đảm bảo được khả năng đáp ứng của tiến trình tốt hơn, khi lập trình đa luồng thì một khi 1 luồng có sự cố thì luồng khác vẫn làm việc, vẫn phản hồi ,trong trường hợp lập trình đơn luồng khi gặp sự cố thì luồng đó sẽ chậm và làm chậm luôn cả tiến trình, đa luồng một ứng dụng giao tiếp cho phép một chương trình tiếp tục chạy thậm chí nếu một phần của nó bị khóa hay đang thực hiện một thao tác dài, do đó gai tăng sự đáp ứng đối với người dùng,
Ví dụ : một trình duyệt web vẫn có thể đáp ứng người dùng bằng một luồng trong khi vẫn nạp bằng một luồng khác.
Ví dụ : Các cô ở tổng đài 108 là các luồng , khi khách hàng điện thoại hỏi 108, thì một trong các cô (người thứ nhất) sẽ trả lời, nếu trong thời điểm đó khách hàng thứ hai gọi 108,thì một trong các cô (cô thứ 2) còn lại sẽ trả lời
- Theo mặc định các luồng có thể dùng chung bộ nhớ và tai nguyên của luồng cha. Thuận lợi của việc chia sẻ mã là nó cho phép một ứng dụng có nhiều hoạt động của các luồng khác nằm trong cùng không gian, địa chỉ,vài luồng cùng vận hành trong một vùng địa chỉ dễ dùng chung tài nguyên hơn so với trường hợp đa tiến trình.
Ví dụ : trong nhà có kệ sách, xe máy, máy vi tính … mọi người có thể dùng chung và sử dụng chung kệ sách, xe máy, máy vi tính. Trong khi không thể dùng chung những đồ dùng trên với nhà khác được
Trong lớp chúng ta có thể dùng bảng củ lớp mình, chúng ta có thể chia sẻ các thông tin cần thiết cho tất cả các thành viên ở trong lớp biết,trong khi chúng ta khong thể dùng chung bảng của lớp khác để chia sẻ thông tin cho lớp mình được.
- Tiết kiệm (Economy) : Cấp phát bộ nhớ và tài nguyên cho tiến trình là công việc rất tốn kém. Do luồng có thể dùng chung tài nguyên với luồng cha và các luồng khác, việc tạo lập ngữ cảnh cũng nhanh hơn
Ví dụ : Các bạn trong lớp là các luồng đang dùng chung một cái bảng của lớp, ai cần ghi thì ghi, ai cần thì chụp hình về xem
Có thể bố trí một chỗ ngồi ở trong lớp cho một bạn đến sau dễ dàng hơn việc làm một chiếc ghế khác cho bạn đó.
- Chuyển ngữ cảnh từ luồng này sang luồng khác thì nhanh hơn chuyển ngữ cảnh từ tiến trình này sang tiến trình khác.
- Tận dụng được ưu thế kiến trúc đa xử lý (nhiều CPU). Khi đa luồng thì 1 luồng dùng CPU này và 1 luồng dùng CPU khác sẽ nhanh hơn và các luồng có thể làm việc song song , mỗi luồng có thể chạy bởi CPU riêng. Tiến trình đa luồng sẽ làm việc nhanh hơn tiến trình đơn luồng.
- Lập trình đa luồng dễ dàng hơn lập trình đa tiến trình .
TranThienTam (I22A)- Tổng số bài gửi : 27
Join date : 08/03/2013
Lập trình đa luồng với C#
Hôm qua đi học thầy có giới thiệu 1 ứng dụng đa luồng viết bằng C# (.Net) sử dụng windowform. Mình thấy ứng dụng rất bổ ích và thực tế. Giờ mình xin phép giới thiệu về lập trình đa luồng với C# sử dụng giao diện console. Bài viết này chỉ là giới thiệu về cách viết lập trình đa luồng chứ không phải 1 ứng dụng như thầy. Bạn nào có hứng thú với C# thì tham khảo nhé
using System;
using System.Threading;
public class MyThread {
public static void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread1 {0}", i);
}
}
public static void Thread2() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread2 {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
Thread tid1 = new Thread(new ThreadStart(MyThread.Thread1 ) );
Thread tid2 = new Thread(new ThreadStart(MyThread.Thread2 ) );
tid1.Start();
tid2.Start();
}
}
Chương trình này có 1 lớp MyThread gồm 2 phương thức tĩnh là Thread1 và Thread2. Để tạo một luồng bạn phải có 1 đối tượng thuộc lớp Thread. Phương thức khởi tạo của lớp này nhận 1 tham chiếu của lớp ThreadStart. Phương thức khởi tạo này có thể gửi 2 kiểu exception (ngoại lệ): ArgumentNullException khi tham số là null hoặc Security Exception khi chương trình không được phép tạo một luồng.
Tham số của lớp Thread là một tham chiếu của lớp ThreadStart. Lớp ThreadStart trỏ đến 1 phương thức có thể được thực hiện trước khi 1 luồng được khởi động. Tham số là tên của phương thức, phương thức này được coi như là phương thức luồng. Thread1 là 1 phương thức tĩnh do đó ta có thể gọi nó bằng tên lớp thay vì tạo một đối tượng. Luồng bắt đầu thực thi với phương thức Start() của lớp Thread. Kết quả sẽ là:
Before start thread
Thread1 0
Thread1 1
Thread1 2
Thread1 3
Thread1 4
Thread1 5
Thread1 6
Thread1 7
Thread1 8
Thread1 9
Thread2 0
Thread2 1
Thread2 2
Thread2 3
Thread2 4
Thread2 5
Thread2 6
Thread2 7
Thread2 8
Thread2 9
using System;
using System.Threading;
public class MyThread {
public static void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread1 {0}", i);
}
}
public static void Thread2() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread2 {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
Thread tid1 = new Thread(new ThreadStart(MyThread.Thread1 ) );
Thread tid2 = new Thread(new ThreadStart(MyThread.Thread2 ) );
tid1.Start();
tid2.Start();
}
}
Chương trình này có 1 lớp MyThread gồm 2 phương thức tĩnh là Thread1 và Thread2. Để tạo một luồng bạn phải có 1 đối tượng thuộc lớp Thread. Phương thức khởi tạo của lớp này nhận 1 tham chiếu của lớp ThreadStart. Phương thức khởi tạo này có thể gửi 2 kiểu exception (ngoại lệ): ArgumentNullException khi tham số là null hoặc Security Exception khi chương trình không được phép tạo một luồng.
Tham số của lớp Thread là một tham chiếu của lớp ThreadStart. Lớp ThreadStart trỏ đến 1 phương thức có thể được thực hiện trước khi 1 luồng được khởi động. Tham số là tên của phương thức, phương thức này được coi như là phương thức luồng. Thread1 là 1 phương thức tĩnh do đó ta có thể gọi nó bằng tên lớp thay vì tạo một đối tượng. Luồng bắt đầu thực thi với phương thức Start() của lớp Thread. Kết quả sẽ là:
Before start thread
Thread1 0
Thread1 1
Thread1 2
Thread1 3
Thread1 4
Thread1 5
Thread1 6
Thread1 7
Thread1 8
Thread1 9
Thread2 0
Thread2 1
Thread2 2
Thread2 3
Thread2 4
Thread2 5
Thread2 6
Thread2 7
Thread2 8
Thread2 9
NguyenHoangThien(I22B)- Tổng số bài gửi : 38
Join date : 15/03/2013
Lập trình đa luồng với C# (tiếp theo)
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread1 {0}", i);
}
}
public void Thread2() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Thread2 {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr.Thread2) );
tid1.Start();
tid2.Start();
}
}
Kết quả của chương trình này giống như chương trình trước đó.
Ta không cần phải tạo 2 phương thức để tạo 2 luồng. Ta chỉ cần tạo 1 phương thức và tạo 2 luồng bằng cách tạo 2 đối tượng thuộc lớp Thread. (Cái này giống như ví dụ về vòng lặp tạo 49 luồng hôm qua của thầy)
Xét đoạn chương trình dưới đây
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Ở đây ta tạo 2 đối tượng thuộc lớp MyThread để thực thi 2 luồng.
Ta không cần phải tạo đối tượng thuộc lớp ThreadStart tại thời điểm truyền tham số vào phương thức khởi tạo. Ta có thể tạo đối tượng thuộc lớp ThreadStart và truyền nó vào như tham số của Thread.
NguyenHoangThien(I22B)- Tổng số bài gửi : 38
Join date : 15/03/2013
Lập trình đa luồng với C# (tiếp theo)
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
ThreadStart tStart1 = new ThreadStart(thr1.Thread1);
ThreadStart tStart2 = new ThreadStart(thr2.Thread1);
Thread tid1 = new Thread(tStart1);
Thread tid2 = new Thread(tStart2);
tid1.Start();
tid2.Start();
}
}
Chương trình này cho kết quả giống như các chương trình trước đó.
Phương thức Sleep ngăn sự thực thi của 1 luồng trong 1 khoảng thời gian xác định. Sleep là 1 phương thức tĩnh do đó có thể được sử dụng mà không cần tạo 1 đối tượng thuộc lớp Thread. Có 2 cách sử dụng Sleep(). Cách 1 là phương thức nhận 1 con số nguyên để tạo thời gian nghỉ (tính bằng giây hoặc mili giây) và cách 2 là nhận một tham chiếu là một thể hiện của cấu trúc TimeSpan
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world " + i);
Thread.Sleep(1);
}
}
}
/////////////////////////////////////////////////
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Bây giờ luồng ngủ trong 1ms và cho luồng thứ 2 thời gian thực thi (chen vào khoảng thời gian nghỉ của luồng 1). Kết quả sẽ là
Before start thread
Hello world 0
Hello world 0
Hello world 1
Hello world 1
Hello world 2
Hello world 2
Hello world 3
Hello world 3
Hello world 4
Hello world 4
Hello world 5
Hello world 5
Hello world 6
Hello world 6
Hello world 7
Hello world 7
Hello world 8
Hello world 8
Hello world 9
Hello world 9
Bây giờ cả 2 luồng dường như là thực thi song song. Sau đây là chương trình cho thấy cách sử dụng khác của phương thức Sleep()
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
int iHour = 0;
int iMin = 0;
int iSec = 1;
Console.WriteLine("Hello world " + i);
Thread.Sleep(new TimeSpan(iHour, iMin, iSec) );
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Cấu trúc TimeSpan có 4 phương thức khởi tạo chồng tên. Phương thức đầu tiên nhận 1 tham số là số tick-tack xác đinh, phương thức thứ 2 nhận 3 số nguyên ứng với giờ, phút, giây, phương thức thứ 3 nhận ngày, giờ , phút, và giây, phương thức thứ 4 nhận 5 tham số ngày, giờ, phút, giây, và mili giây. Kết quả của chương trình này giống với các chương trình trước chỉ khác là chương trình này in 1 giá trị mới sau mỗi 1 giây.
Phương thức Sleep cho 3 exceptions; ArgumentException khi giá trị truyền vào nhỏ hơn 0, ThreadInterruptedException khi luồng bị cắt ngang khi đang ngủ và SecurityException khi đối tượng gọi thực hiện không được cấp quyền thích hợp.
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world {0}", i);
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
ThreadStart tStart1 = new ThreadStart(thr1.Thread1);
ThreadStart tStart2 = new ThreadStart(thr2.Thread1);
Thread tid1 = new Thread(tStart1);
Thread tid2 = new Thread(tStart2);
tid1.Start();
tid2.Start();
}
}
Chương trình này cho kết quả giống như các chương trình trước đó.
Phương thức Sleep ngăn sự thực thi của 1 luồng trong 1 khoảng thời gian xác định. Sleep là 1 phương thức tĩnh do đó có thể được sử dụng mà không cần tạo 1 đối tượng thuộc lớp Thread. Có 2 cách sử dụng Sleep(). Cách 1 là phương thức nhận 1 con số nguyên để tạo thời gian nghỉ (tính bằng giây hoặc mili giây) và cách 2 là nhận một tham chiếu là một thể hiện của cấu trúc TimeSpan
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("Hello world " + i);
Thread.Sleep(1);
}
}
}
/////////////////////////////////////////////////
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Bây giờ luồng ngủ trong 1ms và cho luồng thứ 2 thời gian thực thi (chen vào khoảng thời gian nghỉ của luồng 1). Kết quả sẽ là
Before start thread
Hello world 0
Hello world 0
Hello world 1
Hello world 1
Hello world 2
Hello world 2
Hello world 3
Hello world 3
Hello world 4
Hello world 4
Hello world 5
Hello world 5
Hello world 6
Hello world 6
Hello world 7
Hello world 7
Hello world 8
Hello world 8
Hello world 9
Hello world 9
Bây giờ cả 2 luồng dường như là thực thi song song. Sau đây là chương trình cho thấy cách sử dụng khác của phương thức Sleep()
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
int iHour = 0;
int iMin = 0;
int iSec = 1;
Console.WriteLine("Hello world " + i);
Thread.Sleep(new TimeSpan(iHour, iMin, iSec) );
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Cấu trúc TimeSpan có 4 phương thức khởi tạo chồng tên. Phương thức đầu tiên nhận 1 tham số là số tick-tack xác đinh, phương thức thứ 2 nhận 3 số nguyên ứng với giờ, phút, giây, phương thức thứ 3 nhận ngày, giờ , phút, và giây, phương thức thứ 4 nhận 5 tham số ngày, giờ, phút, giây, và mili giây. Kết quả của chương trình này giống với các chương trình trước chỉ khác là chương trình này in 1 giá trị mới sau mỗi 1 giây.
Phương thức Sleep cho 3 exceptions; ArgumentException khi giá trị truyền vào nhỏ hơn 0, ThreadInterruptedException khi luồng bị cắt ngang khi đang ngủ và SecurityException khi đối tượng gọi thực hiện không được cấp quyền thích hợp.
NguyenHoangThien(I22B)- Tổng số bài gửi : 38
Join date : 15/03/2013
Lập trình đa luồng với C# (tiếp theo)
Sau đây ta hãy xem cách chương trình xử lý khi tham số của Sleep() là số âm.
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
int iHour = 0;
int iMin = 0;
int iSec = -1;
try {
Console.WriteLine("Hello world " + i);
Thread.Sleep(new TimeSpan(iHour, iMin, iSec) );
}
catch (ArgumentException ae) {
Console.WriteLine(ae.Message );
}
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Sau khi chạy chương trình sẽ xuất hiện thông báo mô tả lỗi:
Parameter Name: Argument must be greater than 0 and less than 2^31 - 1milliseconds.
Ta có thể tạo tên của luồng bằng cách dùng thuộc tính Name của lớp Thread.
Bạn nên bắt tất cả các exception có thể xảy ra để tránh tình trạng bị chương trình bị treo khi đang sử dụng
using System;
using System.Threading;
public class MyThread {
public void Thread1() {
for (int i = 0; i < 10; i++) {
int iHour = 0;
int iMin = 0;
int iSec = -1;
try {
Console.WriteLine("Hello world " + i);
Thread.Sleep(new TimeSpan(iHour, iMin, iSec) );
}
catch (ArgumentException ae) {
Console.WriteLine(ae.Message );
}
}
}
}
public class MyClass {
public static void Main() {
Console.WriteLine("Before start thread");
MyThread thr1 = new MyThread();
MyThread thr2 = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr1.Thread1) );
Thread tid2 = new Thread(new ThreadStart(thr2.Thread1) );
tid1.Start();
tid2.Start();
}
}
Sau khi chạy chương trình sẽ xuất hiện thông báo mô tả lỗi:
Parameter Name: Argument must be greater than 0 and less than 2^31 - 1milliseconds.
Ta có thể tạo tên của luồng bằng cách dùng thuộc tính Name của lớp Thread.
Bạn nên bắt tất cả các exception có thể xảy ra để tránh tình trạng bị chương trình bị treo khi đang sử dụng
NguyenHoangThien(I22B)- Tổng số bài gửi : 38
Join date : 15/03/2013
Trang 4 trong tổng số 8 trang • 1, 2, 3, 4, 5, 6, 7, 8
Similar topics
» Ôn tập thi Cuối kỳ
» Thảo luận các vấn đề của Môn học
» Thảo luận Bài 3
» Thảo luận bài 4
» Thảo luận Bài 7
» Thảo luận các vấn đề của Môn học
» Thảo luận Bài 3
» Thảo luận bài 4
» Thảo luận Bài 7
Trang 4 trong tổng số 8 trang
Permissions in this forum:
Bạn không có quyền trả lời bài viết