Giới thiệu thư viện PTHREAD POSIX
Trang 1Chương 3: Giới thiệu thư viện
PTHREAD POSIX (POSIX, Portable Operating System Interface)
1) Hướng dẫn cài đặt PTHREAD POSIX với VC++ 6
*) Biên dịch
- Copy thư viện hàm pthread, có thư mục: Pre-built.2
- Thiết lập thư mục pthread\Pre-built.2\include;pthread\Pre-built.2\lib vào option
của VC++6 bằng cách chọn Tools->Option->Directories
- Copy pthreadVC2.dll vào C:\WINDOWS\system32
*) Chạy chương trình:
- Cấu hình project trong VC++: chọn Project ->Settings -> Link -> thêm
pthread.lib vào ô có tiêu đề
Object/library modules
2) Nhắc lại một số kiến thức quan trọng trong C++
- Con trỏ không kiểu
Con trỏ không kiểu là một loại con trỏ đặc biệt Nó có thể trỏ tới một kiểu dữ liệu bất kỳ, từ giá trị số cho tới một xâu kí tự Hạn chế duy nhất của nó là dữ liệu được trỏ tới không thể được tham chiếu tới một cách trực tiếp (chúng ta không thể dùng toán tử tham chiếu * với chúng) vì độ dài của nó là không xác định và vì vậy chúng ta phải dùng đến toán tử biến đổi kiểu dữ liệu hay phép gán để biến đổi con trỏ không kiểu thành một con trỏ trỏ tới một loại dữ liệu cụ thể
Một trong những tiện ích của nó là cho phép dùng tham số cho hàm mà không cần chỉ rõ kiểu, vd:
case sizeof(char) : (*((char*)data))++; break;
case sizeof(short): (*((short*)data))++; break;
case sizeof(long) : (*((long*)data))++; break;
Trang 2ngoặc đơn () tên của hàm và chèn dấu sao (*tenthamsocontroham) đằng trước
Trong ví dụ này, minus là một con trỏ toàn cục trỏ tới một hàm có hai tham số kiểu int, con trỏ này được gám để trỏ tới hàm subtraction, tất cả đều trên một dòng:
int (* minus)(int,int) = subtraction;
3) Giới thiệu các hàm chính của pthread
- Tạo thread
int pthread_create (pthread_t *thread, const pthread_attr_t *attr,
void* (*start_routine) (void *), void *arg) ;
thread: Một định danh ID duy nhất cho thread mới
attr: Lưu trữ các tham số của thread mới, mặc định là Null
start_routine: Địa chỉ của chương trình con mà chúng ra cần chạy trong thread mới này
arg: Các tham số của chương trình con, mặc định là NULL
- Kết thúc thread
void pthread_exit (void *value_ptr);
- Thu hồi và kết thúc thread
int pthread_join ( pthread_t inHandle, void
**outReturnValue);
Thực hiện việc thu hồi bộ nhớ và các thiết của thread có định danh
inHandle Thread cha bị block, và phải chờ cho đến khi thread inHandle kết
thúc
Trang 34) Ví dụ tạo lập và kết thúc thread
Chương trình chính (thread chính) tạo ra một thread con để làm một việc gì
đó cho mình Trong ví dụ này chương trình sẽ in ra chữ “Hello, World!”, trong
đó thread con in “Hello, ”, còn thread chính in “World!”
//1 Khai bao thu vien
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 2 Viet ham con tro; Se goi cac ham nay khi chung ta tao thread
void *print_hello(void *args)
Trang 4if (pthread_create(&tid, NULL, print_hello, NULL))
5) Trao đổi dữ liệu giữa thread chính với các thread con:
Mỗi thread sẽ thi hành một chương trình con, và chương trình chính có thể trao đổi dữ liệu với nó Thông thường thread chính sẽ giao nhiệm vụ và dữ liệu nguồn cho các tiến trình con; các tiến trình con sau khi tính toán xong lại gửi kết quả về cho tiến trình chính
5.1) Truyền dữ liệu cho các thread thông qua tham số của pthread_create
VD 5.1: Truyền ID của các thread cho các chương trình con
Các chương trình con in cac ID cua thread ra man hinh
Chuong trinh chinh tao ra N thread (cac thread con in ra chinh ID cua minh)
Trang 5{
//taskID[t]=t;
//printf("Creating thread %d\n", taskID[t]);
rc = pthread_create(&thread[t], NULL, BusyWork, &t);
//rc = pthread_create(&thread[t], NULL, BusyWork, &taskID[t]);
void *PrintHello1(void *threadid)
{ int *id_ptr, taskid;
Sleep(10);
id_ptr = (int *) threadid;
Trang 6//Tham so thuc su là dữ liệu kiểu cấu trúc Data
void *PrintHello2(void *threadata)
messages[0] = "English: Hello World!";
messages[1] = "French: Bonjour, le monde!";
messages[2] = "Spanish: Hola al mundo";
exit(-1); } }
Trang 75.2) Các thread trả kết quả về cho thread chính thông qua pthread_join
int pthread_join ( pthread_t inHandle, void
**outputReturnValue);
VD 1: Tạo 3 thread, mỗi thread tính tổng của 10 số ngẫu nhiên
#include <pthread.h>
Trang 8#include <stdio.h>
#include <stdlib.h>
#define N_THREADS 3// so thread con
void *BusyWork(void *null)
{
int i;
double *result=new double (0.0);// cac bien cuc bo cua tung thread
for (i=0; i<10; i++)
Trang 9int h=(int) array_size/N_Thread;
void input() { int i;
for (i=0;i<array_size; i++)
a[i]=1;
} void *Worker(void *myThread)// so sanh myThread voi myDataThread { int id,i,*tg;
Trang 10} void main() { pthread_t *threads;
int i; int tasks[N_Thread ];
input();
threads= new pthread_t[N_Thread ];
for (i=0; i<N_Thread ; i++)
{
tasks[i]=i;
if (pthread_create(threads+i,NULL, Worker,&tasks[i])) {
perror("Error");exit(1);
} }
}
5.3) Các thread trả kết quả về cho thread chính thông qua tham biến của
pthread_create
VD: Tính tổng của dãy A gồm n số nguyên với việc sử dụng m thread
(n chia het cho m) Thuat toan:
Chia deu n ptu cho m thread => moi thread tinh tong cua h=n/m ptu
Đánh so cac thread: 0 => m-1, thì
Thread 0: tinh tong cac ptu tu 0 den h-1
Thread 1: tinh tong cac ptu tu h den 2h-1
…
=> Goi id chi so cua mot thread nao do => thread phai tinh tong cac ptu tu id*h den (id+1)h – 1
#include <stdio.h>
Trang 11*/
int h=(int) N/M;
struct Data {
Data data[M];
input();
Trang 12threads= new pthread_t[M];
for (i=0; i<M; i++)
for (i=0;i<M;i++)
{ pthread_join(threads[i], NULL);
}
int Sum=0;
for (i=0;i<M;i++) {
Sum +=data[i].sum ; }
printf("Sum=%d",Sum);
} 5.4) Các thread con trả kết quả về cho chương trình chính thông qua biến toàn cục
Trang 13int i;
for (i=0;i<N; i++)
a[i]=1;
} void *Worker(void *myThread) { int i,tg,id;
threads= new pthread_t[M];
for (i=0; i<M; i++)
for (i=0;i<M;i++)
{ pthread_join(threads[i],NULL);
} int Sum=0;
Trang 14for (i=0;i<M;i++) {
Sum +=sum[i] ; }
( (
) (
i i
i b
a
x f x
f h S
S dx
x f
∫ +
= 10
2
1 4
π
Trang 15threads= new pthread_t[numt];
taskids= new int[numt];
h = (b - a) / n;
for(i = 0; i < numt; i ++)
{
Trang 16// pthread_create(threads + i, NULL, worker, (void*)&i);
6) Sự khác nhau giữa thread và chương trình con:
VD: Minh hoạ sự khác nhau giữa thread và trình con Sự dụng thread để thực hiện song
song các chương trình con first_function(), và second_function()
pthread_create(&thread1, NULL, (void*) first_function, (void*)&i);
pthread_create(&thread2, NULL, (void*) second_function, (void*)&j);
trong khi chương trình con final_function() thì khi nào gọi tới nó mới chạy
Trong chương trình này ta khởi tạo 2 thread, mỗi thread làm một việc
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
Hai câu lệnh trên yêu cầu chương trình chính chờ cho đến khi thread1,
thread2 kết thúc, sau đô kết quả tính toán của 2 thread được chương trình con
final_function() gom lại Khi chương trình con gom kết quả thì các thread đã
không còn tồn tại, tuy vậy kết quả của nó được để ở trong 2 ô nhớ “i” và “j” đã
tạo sẵn ngay trong trình chính
//printf("%d \n",(*(int *) num));
Trang 17for(x=0; x< 50; x++) { printf("Inside the first_function\n");
for (y=0; y< 1000; y++) z =z+1; /* introduce delay*/
(*(int*)kq1)++;
} return NULL;
}
void *second_function(void *kq2) { int x,y,z;
for(x=0; x< 20; x++) { //printf("Inside the second_function\n");
//for (y=0; y< 1000; y++) z =z+1; /* introduce delay*/
(*(int *)kq2)++;
}
Return NULL;
} void final_function(int first, int second) { int final_score;
final_score = first + second ; printf("In final : first = %d, second = %d and final_score = %d\n", first, second, final_score);
}
void main() {
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, first_function, (void*)&i);
pthread_create(&thread2, NULL, second_function, (void*)&j);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
final_function(i,j);
}
7) Tháo gỡ các Threads ( Detaching Threads)
- Hàm int pthread_detach(thread_t tid); giải phóng ngay lập tức vùng nhớ đã cung cấp cho thread này khi nó kết thúc
- Với các ứng dụng cần phải giải phóng vùng nhớ ngay khi các thread kết thúc thì chúng
ta phải tạo các thread với thuộc tính PTHREAD_CREATE_JOINABLE và sau đó
Trang 18sử dụng pthread_join()hoặc pthread_detach()để giải phóng vùng nhớ
double x;
int i;
int j;
} ; double f(double x) {
return x*x;
} void *thread_f(void *arg) {
DATA* a = (DATA*)arg;
X[a->i][a->j] = f(a->x);
return NULL;
} void main() {
Trang 19} DATA *arg;
for ( i=0;i<SIZE_I; ++i) {
for (int j=0; j<SIZE_J; ++j) {
arg = new DATA;
arg->i = i; arg->j = j; arg->x = Y[i][j];
pthread_create(&thread, NULL, thread_f, (void *)arg); // tach thanh cac thread chay doc lap
//ret = pthread_detach(thread);
//printf ("Trang thai % d \n",ret);// tra ve 0 neu thread kethuc thanh cong
} }
} }
7) Bài tập áp dụng
7.1) Tính tổng một dãy số
7.2) Bài toán tính tổng 2 véctơ
Giả sử có 2 vector A[N] và B[N]
C[i]=A[i]+B[i];
7.3) Bài toán sắp xếp so sánh và đổi chỗ
Ví dụ: n = 8 và dãy số ban đầu là 4, 2, 7, 8, 5, 1, 3, 6
Trang 205 1 2 3 4 5 7 6 8
Hình 5-4 Sắp xếp theo nguyên lý hình ống // M = N/2
+ M : N*N chia het cho M =>
Cach 1: phan deu cong viec cho cac thread => N*N/M
Trang 21perror("Error");exit(1);
} }
Trang 22tg=a[2*id];a[2*id]=a[2*id+1];a[2*id+1]=tg;
kt=1;
} }
else
{
if (id<NUM-1) {
if (a[2*id+1]>a[2*id+2]) {
tg=a[2*id+1];a[2*id+1]=a[2*id+2];a[2*id+2]=tg; kt=1;
} }
}
Trang 24static int N, nrow;
static double *A, *B, *C;
void setup_matrices ()
{
int i, j;
A = new double[N*N];//malloc (N * N * sizeof (double));
B = new double[N*N];//malloc (N * N * sizeof (double));
C = new double[N*N];//malloc (N * N * sizeof (double));
Trang 25nthreads = atoi (argv[1]);
threads = new pthread_t[nthreads];//malloc (nthreads * sizeof (pthread_t));
Trang 26N = atoi (argv[2]);
setup_matrices ();
for (i = 0; i < nthreads; i++)
pthread_create (threads + i, NULL, worker, NULL);
for (i = 0; i < nthreads; i++)
pthread_join (threads[i], NULL);
//if (argc > 3)
print_result ();
pthread_mutex_destroy(&mut);
}