1. Trang chủ
  2. » Công Nghệ Thông Tin

Tạo lập thread - bài tập thread docx

20 589 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 241 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

1 pthread_attr_init&attr; 2 pthread_attr_setdetachstate&attr, PTHREAD_CREATE_JOINABLE; 3 pthread_create&threads[0], &attr, inc_count, void*&thread_ids[0]; Lệnh 1 tạo ra biến attr để nhớ

Trang 1

I.1 Tạo lập thread

I.1.1 Thiết lập Thuộc tính cho thread

1) pthread_attr_init(&attr);

2) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

3) pthread_create(&threads[0], &attr, inc_count, (void*)&thread_ids[0]);

Lệnh 1) tạo ra biến attr để nhớ thuộc tính, lệnh 2) nạp thuộc tính cho nó – ở đây thuộc tính được chỉ định là “PTHREAD_CREATE_JOINABLE”, lệnh 3) chỉ định thread có thuộc tính attr Chúng ta thường sử dụng thuộc tính ngầm định NULL, chỉ thị này cho phép các thread “join” được với trình chính

I.1.2 Tạo lập, Giao nhiệm vụ & Truyền tham số cho thread

I.1.2.A Các bước cơ bản.

Để tạo lập và điều kiển một thread ta cần phải thực hiện 5 bước cơ bản sau

1 Mô tả thread: void * proc_1(int x,y)

2 Đăng ký thread: pthread_t tid;

3 Khởi tạo (đăng ký thuộc tính), giao nhiệm vụ, và truyền dữ liệu

pthread_create(&tid, NULL, &proc_1, (void*)&arg);

4 Xác định thread pthread_equal(pthread_self(), )

“Mô tả thread” là việc tạo ra một trình con Nó chính là thread sau này Các lệnh còn lại chỉ là thủ tục để cho trình con này biến thành thread, tức là chạy song song và có các thuộc tính cần thiết

Các lệnh này gồm có

1) Lệnh khởi tạo và giao nhiệm vụ pthread_create

Trang 2

Lệnh này kết nối một thread với một hàm con (được gọi tắt là thread1, hay hàm được kích hoạt thành thread) Lệnh còn đảm nhận trách nhiệm truyền dữ liệu cho thread Dữ liệu phải được khai báo trước và để ở đâu đó trong bộ nhớ Tuy nhiên không phải các dữ liệu này được truyền cho thread, mà chỉ là địa chỉ của những khối dữ liệu cần phải truyền, mà thôi Các địa chỉ là các con trỏ – nó có thể là địa chỉ của một vùng nhớ, và cũng có thể là biến địa chỉ chứa địa chỉ của vùng nhớ có dữ liệu Ví dụ, nếu cần truyền giá trị chứa trong biến

X thì (do địa chỉ của X là &X) chỉ thị truyền là (void*)&X Còn nếu địa chỉ của dữ liệu được để trong con trỏ P thì chỉ thị truyền là (void*)P Do chỉ được truyền cho địa chỉ, cho nên, để có thể sử dụng được những dữ liệu này, thread phải tự định dạng các dữ liệu này sao cho hợp với dạng vốn có của chúng

2) Lệnh kết thúc hoạt động pthread_join

Lệnh này đóng vai trò đồng bộ thread với trình chính2 Số là, tiến trình chính, sau khi khởi tạo ra các thread, thì vẫn tiếp tục hoạt động – và các thread do nó tạo ra thì chạy song song với nó Nếu trình chính mà muốn sử dụng một kết quả nào đó do thread tính ra, thì nó phải biết được thời điểm mà thread kết thúc hoạt động của mình Trình chính không thể tự biết được thời điểm các thread kết thúc hoạt động, vì vậy cần phải có một lệnh – và đó chính là

lệnh pthread_join – bắt trình chính (nếu nó đến lệnh này sớm hơn) phải chờ để thread kết

thúc công việc của mình Điều này hàm ý, ở lệnh tiếp theo sau lệnh nó, thread tương ứng

đã không còn nữa3 Lệnh pthread_joint chỉ thị chờ cho từng thread một, và chính vì vậy trong chỉ thị lệnh phải có thông báo tên của thread cần “join” với trình chính – hay trình chính phải chờ

I.1.2.B Ví dụ về tạo lập & truyền dữ liệu cho thread.

Ví dụ 1 Tạo lập thread.

Trình chính (thread chính) tạo ra một thread để làm một việc gì đó cho mình Trong ví dụ này thread in “Hello, ” còn trình chính in “World!” Do thread chạy song song với trình chính mà các từ in ra không theo thứ tự nhất định, nó có thể là “Hello World” và cũng có thể là “World Hello”

#include <iostream.h>

#include <pthread.h>

void * print_hello(void *args) { cout<<"Hello, ";return NULL;}

void *main()

1 Trên thực tế mỗi khi lệnh này được gọi thì có 2 thread được tạo ra Thread “con” dùng để chạy trình con và thread “mẹ” để chạy trình chính Như vậy thread và trình chính đều là các thread Thread “con” có thể có được những tính chất như quyền ưu tiên, lịch hoạt động, thời điểm kết thúc hoạt động (đồng bộ hay không)

2 Thời điểm kết thúc hoạt động của một thread có thể là đồng bộ hay là không đồng bộ Nếu một thread được khai báo là “kết hợp” (joined) thì nó chỉ thực sự kết thúc hoạt động (hủy bỏ hoàn toàn

bộ nhớ do nó tạo ra như stack và header) khi lệnh trình chính gọi lệnh “pthread_join()” Ngược lại nếu nó thuộc loại “tách rời” (detached) thì nó sẽ giải phóng tất cả bộ nhớ do nó tạo ra khi nó kết thúc hoạt động

3 Lưu ý lệnh này không hủy bỏ vùng bộ nhớ mà thread đã xin cấp.

Trang 3

{ pthread_t tid; pthread_create(&tid, NULL, &print_hello, NULL);

cout<<"World! ";

pthread_join(tid, NULL);

return NULL;

}

Ví dụ 2 Truyền dữ liệu.

Do đặc thù của tính song-song trong xử lý mà chúng ta cần phải tin chắc rằng khoảng thời gian kể từ lúc một thread được tạo ra cho đến lúc nó hoạt động là phải được khống chế và

là phải là không đáng kể Điều này hàm ý là tổng thời gian thực tế cần thiết để truyền dữ liệu cho nó phải là rất ít – diễn ra trong khoảng một vài lệnh asambly Như vậy, giao nhiệm

vụ cho thread cũng như cấp dữ liệu cho nó đều là thông qua con trỏ Con trỏ sẽ trỏ tới địa chỉ, nơi lưu giữ trình con cần phải được kích hoạt để chạy song song; con trỏ sẽ trỏ tới vùng dữ liệu nơi lưu giữ dữ liệu cần cho thread Tóm lại nguyên lý truyền dữ liệu cho một thread là “truyền con trỏ đến vùng dữ liệu”

Sau đây là ví dụ về việc truyền nói trên Hàm được kích hoạt là “Say” Đó là một hàm được khai báo ở dạng con trỏ, và chính con trỏ này sẽ được truyền cho thread để thông báo hàm cần phải được kích hoạt Hàm này sẽ in ra màn hình lời chào bằng ở các ngôn ngữ khác nhau Dữ liệu cần truyền cho thread để nó hoạt động là các dòng chữ và chúng ta không truyền hẳn cho các thread cả dòng chữ, bở dung lượng dữ liệu phải truyền sẽ rất nhiều vì các dòng này tương đối dài, mà chúng ta chỉ truyền cho nó địa chỉ nơi lưu giữ các lời chào đó Trong ví dụ sau, trình chính tạo ra và truyền dữ liệu cho 3 thread chạy song song Mỗi thread in ra một dòng thông báo trên màn hình Các dòng chữ đó là các câu chào (đã để sẵn trong bộ nhớ, trong một mảng) ở các ngôn ngữ khác nhau: "English: Hello World!", "French: Bonjour, le monde!", "Vietnam: Chao tat ca" Để làm được việc này, mỗi thread nhận được địa chỉ ứng với vị trí dòng chữ tương ứng

#include <iostream.h>

#include "pthread.h"

#include <string>

using namespace std;

#define NUM 3

string mess[NUM];

void *Say(void *messages)

{ cout<< (char *) messages << "\n";

pthread_exit(NULL);

return NULL;

}

void *main(int argc, char *argv[])

{ pthread_t threads[NUM];

mess [0] = "English: Hello World!";

mess [1] = "French: Bonjour, le monde!";

mess [2] = "Vietnam: Chao tat ca!";

for(int t=0;t<NUM;t++) {pthread_create(&threads[t], NULL, &Say,(void *) mess[t].c_str());}

for(t=0;t<NUM;t++) pthread_join(threads[t],NULL);

return NULL;

}

Trang 4

Dữ liệu có thể được lưu dưới dạng mảng và truyền cho các thread chỉ số của mảng Việc làm này thường dùng khi sử dụng mảng thread, nó cho phép chúng ta sử dụng vòng lặp

“for” để tạo lập giao nhiệm vụ và truyền dữ liệu cho các thread

#include <stdio.h>

#include <malloc.h>

#include "pthread.h"

#define NUM 3

char *messages[NUM];

void *PrintHello(void *threadid)

{ int *id_ptr, taskid;

id_ptr = (int *) threadid;

taskid = *id_ptr;

printf("Thread %d: %s\n", taskid, messages[taskid]);

pthread_exit(NULL);

return NULL;

}

void main(int argc, char *argv[])

{ pthread_t threads[NUM];

int *taskids[NUM];

int t;

messages[0] = "English: Hello World!";

messages[1] = "French: Bonjour, le monde!";

messages[2] = "Vietnam: Chao tat ca!";

for(t=0;t<NUM;t++)

{ taskids[t] = (int *) malloc(sizeof(int)); *taskids[t] = t;

pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);

}

for(t=0;t<NUM;t++) pthread_join(threads[t],NULL);

}

/*Result:

Thread 0: English: Hello World!

Thread 1: French: Bonjour, le monde!

Thread 2: Vietnam: Chao tat ca!

Press any key to continue

*/

Lưu ý rằng, việc truyền trực tiếp giá trị “t” sẽ dẫn đến sai lầm, bởi vì, vào thời điểm thread hoạt động thì (do vòng for làm nó tăng lên) giá trị “t” ấy, có thể, đã khác đi rồi!

Như vậy khúc trình sau đây là sai

for(t=0;t<NUM;t++)

{ printf("Creating thread %d\n", t);

rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &t);

if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } }

Ví dụ 3 Truyền nhiều dữ liệu cho thread.

Có thể truyền nhiều dữ liệu bằng cách liệt kê, và cũng có thể truyền con trỏ – trỏ tới tới một cấu trúc hay một Object

Trang 5

Ví dụ 4 Truyền dữ liệu cho thread thông qua việc truyền con trỏ tới một cấu trúc có chứa

nhiều trường với định dạng khác nhau

#include <iostream.h>

#include "pthread.h"

#include <string>

#define NUM 3

using namespace std;

string mess[NUM];

struct wrapper

{ int id;

string message;

} data_array [NUM];

void * PrintHello(void* data)

{ cout<< ((wrapper*)data)->id << " > ";

cout<< ((wrapper*)data)->message.c_str() << "\n";

return NULL;

}

void *main()

{ pthread_t threads[NUM];

for(int t=0;t<NUM;t++)

{

switch (t){

case 0: data_array[0].message="Thread 0";

case 1: data_array[1].message="Thread 1";

case 2: data_array[2].message="Thread 2";

}

data_array[t].id = t;

pthread_create(&threads[t], NULL, PrintHello, (void *) & data_array[t]);

}

for(t=0;t<NUM;t++){pthread_join(threads[t], NULL);}

return NULL;

}

/*Result:

0 > Thread 0

1 > Thread 1

2 > Thread 2

*/

Ví dụ 5 Các thread có thể là hàm của một class, nhưng hàm này phải thuộc loại được khai

báo “static”

#include <iostream.h>

#include "pthread.h"

class Hello{

public:

static void* print(void* msg);

Trang 6

void* main()

{ pthread_t thread1, thread2;

char *message1="Hello ";

char *message2="World \n";

pthread_create(&thread1,NULL,Hello::print,(void *)message1);

pthread_create(&thread2,NULL,Hello::print,(void *)message2);

pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

return NULL;

}

void * Hello::print(void* msg)

{ char *message;

message= (char *)msg;

cout<<message;

return NULL;

}

/*Result:

Hello World

*/

Ví dụ 6 Các thread có thể là hàm của một object, nhưng hàm này phải thuộc loại được

khai báo “static”

#include <iostream.h>

#include "pthread.h"

class Hello{

public:

static void* print(void* msg);

};

void * main()

{ pthread_t thread1, thread2;

Hello *H=new Hello;

char *message1="Hello ";

char *message2="World \n";

pthread_create(&thread1,NULL,H->print,(void *)message1);

pthread_create(&thread2,NULL,H->print,(void *)message2);

pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

return NULL;

}

void * Hello::print(void* msg)

{ char *message;

message= (char *)msg;

cout <<message;

return NULL;

}

/*

Hello World

Trang 7

Ví dụ 7 Thủ tục của một Object được kích hoạt thành thread.

#include <iostream.h>

#include "pthread.h"

class ThreadClass;

struct wrapper

{ ThreadClass* Me;

int a;

};

class ThreadClass

{public:

int a;

static void* function(void* arg)

{ wrapper* Unpack = (wrapper*) arg;

ThreadClass* Hidden= Unpack->Me; Hidden->a = Unpack->a; cout<<"I got: " << Hidden->a <<"\n";

return NULL;

}

};

int main()

{ pthread_t Thread1; int one = 1;

ThreadClass Test;

wrapper ToPass; ToPass.Me = &Test; ToPass.a = one;

pthread_create(&Thread1, NULL, Test.function, &ToPass);

pthread_join(Thread1, NULL);

return 0;

}

/*Result:

I got: 1

Press any key to continue

*/

Ví dụ 8 Sử dụng thủ tục “static” để gọi các thủ tục “non static”.

#include <iostream.h>

#include "pthread.h"

class Hello{

public:

void* print(void* msg);

static void * test(void* arg); //the entry static function

};

struct pack_data{

Hello * self;

char * str_content;

}; //the wrapper

void *main()

{ pthread_t thread1, thread2;

Hello *H= new Hello;

Trang 8

struct pack_data *pk1 = new pack_data; pk1->self=H; pk1->str_content="Hello "; struct pack_data *pk2 = new pack_data; pk2->self=H; pk2->str_content="World \n"; pthread_create(&thread1,NULL,H->test,(void *)pk1);

pthread_create(&thread2,NULL,H->test,(void *)pk2);

pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

return NULL;

}

void * Hello::print(void* msg) //non static function

{ char *message;

message= ((pack_data *)msg)->str_content;

cout<< message;

return NULL;

}

void * Hello::test(void *arg) //static function

{ Hello *ptr= new Hello;

ptr= ((pack_data *)arg)->self;

ptr->print(arg); //call a static function

return NULL;

}

/*Result:

Hello World

Press any key to continue

*/

I.1.2.C Tạo mảng thread

Ví dụ 1 Trong ví dụ sau một mảng thread được tạo ra và được giao nhiệm vụ Nhiệm vụ

chỉ đơn thuần là mỗi thread chạy 4 lần, in ra màn hình số thứ tự của mình, rồi kết thúc nhiệm

#include <stdlib.h>

#include <malloc.h>

#include <stdio.h>

#include "pthread.h"

void *do_one_thing(void *pnum)

{ int i; for (i = 0; i < 4; i++) { printf("%d is doing a thing\n", (int *)pnum); }return NULL;}

void main()

{ int i, n=5;

pthread_t *thread1;

int* Nthread;

thread1 = (pthread_t *) calloc(n, sizeof(pthread_t)); Nthread = (int *) calloc(n, sizeof(int));

for(i=0;i<n;i++){

Nthread[i]=i;

pthread_create(&(thread1[i]), NULL, &do_one_thing, (void*)Nthread[i]);

}

for(i=0;i<n;i++){pthread_join(thread1[i], NULL);}

Trang 9

free(Nthread); free(thread1);

return;

}

Ví dụ 2 Trong ví dụ này mảng 10 Object, đánh số từ 0 9, thuộc Class “ThreadClass” được

tạo ra Trong mỗi Object có một hàm được kích hoạt thành thread – khi chạy nó sẽ in ra màn hình số hiệu của Object Có thể quan niệm 10 Object này tồn tại và vận hành độc lâp Lệnh pthread_join chỉ kết thúc hoạt động của các hàm, trong khi 10 Object này vẫn tồn tại

#include <iostream.h>

#include "pthread.h"

class ThreadClass

{public:

int a;

static void* function(void* arg)

{ cout<<" I am Object: " << (int)((ThreadClass *) arg)->a <<"\n";return NULL;}

};

int main()

{ int i;

pthread_t Thread[10];

ThreadClass Test[10]; for (i=0; i<10;i++){Test[i].a=i;}

for (i=0; i<10;i++){ pthread_create(&Thread[i], NULL, Test[i].function, &Test[i]); } for (i=0; i<10;i++) pthread_join(Thread[i], NULL);

return 0;

}

I.1.3 Sự khác nhau giữa thread và trình con

I.1.3.A Thread là trình con được kích hoạt để chạy song song.

Trong ví dụ sau hai thread là các trình con first_function(), và second_function() nhưng

được kích hoạt để chạy song song

pthread_create(&thread1, NULL, &first_function, &i);

pthread_create(&thread2, NULL, &second_function, &j);

Để thấy được dấu hiệu chạy song song của hai thread này, chúng ta ra lệnh cho mỗi thread liên tiếp in ra 10 lần thông báo về mình Khi chạy khúc trình sau chúng ta sẽ sớm nhận ra các thông báo hiện ra trên màn hình đan xen kẽ vào nhau, chứng tỏ chúng hoạt động thật

sự song song

Trong ví dụ này final_function() là trình con bình thường và chỉ khi nào gọi tới nó mới

chạy Các thread được khởi tạo, và mỗi thread làm một việc Khi kết thúc công việc, pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

kết quả tính toán của 2 thread được trình con gom lại Khi 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 Trình final_function() sẽ dùng các kết quả này

1 #include <stdio.h>

2 #include "pthread.h"

3 int i=0, j=0;

Trang 10

4 void * first_function(void *num)

5 { int x,y,z=0;

6 int * a =(int*)num;

7 for(x=0; x< 10; x++)

8 { printf("Inside the first_function %d\n",*a);

9 for (y=0; y< 1000; y++) z =z+1;

10 (*a)++;

11 }

12 num=a;

13 return NULL;

14 }

15 void * second_function(void *num)

16 { int x,y,z=0;

17 int * a =(int*)num;

18 for(x=0; x< 20; x++)

19 { printf("Inside the second_function %d\n",*a);

20 for (y=0; y< 1000; y++) z =z+1;

21 (*a)++;

22 }

23 num=a;

24 return NULL;

25 }

26 void final_function(int first, int second)

27 { int final_score;

28 final_score = first + second ;

29 printf("In final: first = %d, second = %d and final_score = %d\n", first, second,

final_score);

30 }

31 void main()

32 { pthread_t thread1, thread2;

33 pthread_create(&thread1, NULL, &first_function, &i);

34 pthread_create(&thread2, NULL, &second_function, &j);

35 pthread_join(thread1, NULL);

36 pthread_join(thread2, NULL);

37 final_function(i,j);

38 }

Kết quả hiện ra là

In final : first = 10, second = 20 and final_score = 30

đó là số lần lặp các vòng lặp trong hai thread Sự việc sẽ không còn đơn giản như vậy nữa nếu chúng ta bỏ các lệnh (35) và (36) và khi ấy trên màn hình sẽ hiện ra thông báo:

In final : first = 0, second = 0 and final_score = 0

Thông báo này chứng tỏ các thread, tuy có chạy, nhưng không rõ các thông số về chúng ra sao

I.1.3.B Thread, Trình con, và Màn hình.

Trong ví dụ sau một trình con được tạo ra để in lên màn hình các số từ 0 đến 9 Một lần gọi

Ngày đăng: 04/07/2014, 03:20

TỪ KHÓA LIÊN QUAN

w