Ví dụ cơ bản với pthread trên Linux
1. Tạo và dừng thread
Source code gốc lấy từ link
/******************************************************************************
* FILE: hello.c
* DESCRIPTION:
* Chuong trinh demo thao tac tao thread, tat thread
* AUTHOR: Blaise Barney
* LAST REVISED: 08/09/11
*
* TRANSLATE to Vietnamese by Minatu
* COMPILE CMD : $gcc -o hello hello.c -lpthread
******************************************************************************/
//
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
printf("Hello World! Thread #%ld o day !!!n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
int rc;
long tId;
for (tId = 0; tId < NUM_THREADS; tId++) {
printf(" Ham main() : Thread Main : Tao...thread moi: %ldn", tId);
rc = pthread_create(&threads[tId], NULL, PrintHello, (void *)tId);
if (rc) {
printf("ERROR; loi khi chay pthread_create(), ma loi: %dn", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
}
Kết quả sau khi biên dịch và chạy:
oedev@OEDEV-Ubuntu:code$ gcc -o hello hello.c -lpthread
oedev@OEDEV-Ubuntu:code$ ./hello
Ham main() : Thread Main : Tao...thread moi: 0
Ham main() : Thread Main : Tao...thread moi: 1
Hello World! Thread #0 o day !!!
Ham main() : Thread Main : Tao...thread moi: 2
Hello World! Thread #1 o day !!!
Ham main() : Thread Main : Tao...thread moi: 3
Ham main() : Thread Main : Tao...thread moi: 4
Hello World! Thread #2 o day !!!
Hello World! Thread #3 o day !!!
Hello World! Thread #4 o day !!!
Như ta thấy, các thread được tạo và chạy hàm PrintHello
rồi hiển thị giá trị tId
được truyền khi tạo trong nội dung của nó.
Ta chú ý ở đây, thông tin hiện ra màn hình có thể không theo thứ tự đâu.
Tức là có thể dù thread 1 được tạo trước thread 2 nhưng chưa chắc chữ Hello World
của nó sẽ ra trước thread 2.
Nói kĩ hơn về các hàm sử dụng ở trên:
rc = pthread_create(
&threads[tId],
NULL,
PrintHello,
(void *)tId);
Trong đó,
- Tham số thứ nhất:
&threads[tId]
: Chứa các thông tin của thread sau khi được tạo.
Bất cứ thao tác nào liên quan đến thread này đều thông qua biến này.
-
Tham số thứ 2 :
NULL
: Tức là không set thêm thuộc tính nào cho thread sẽ được tạo,
lấy hết mặc định. -
Tham số thứ 3 :
PrintHello
: Hàm (hoặc con trỏ hàm) sẽ chạy trong thread sau khi được tạo.
Thông thường hàm này sẽ chạy mãi bằng một vòng lặp vô tận chẳng hạn. -
Tham số thứ 4 :
(void*)tId
: Tham số này là một con trỏ thôi, kiểu gì cũng được.
Nó sẽ được truyền như là tham số như thread thực hiện hàm đã truyền ở tham số thứ 3.
Trong trường hợp này hàmPrintHello
nhận tham sốvoid *
vì thế nên ép kiểu sang
void *
chotId
. Và ta cũng thấy, giá trịtId
được ép kiểu trở lại trong hàmPrintHello
Tiếp theo đến
pthread_exit(NULL);
- Tham số của hàm này ở đây được sử dụng để truyền ra cho một thread khác đang đợi bằng
join
nó kết thúc, trong trường hợp này không sử dụng nên giá trị nó là NULL.
2. Thêm một chút xử lý cho thread
-
Giả sử mỗi thread chạy một vòng lặp vô hạn, sẽ in giá trị tăng dần đến các terminal (được bật sẵn)
khác nhau. -
Để đơn giản, ta sử dụng 4 terminal.
1 Terminal (gọi là Terminal 0) để cho thread chính hay chính cái xử lý chứa hàmmain()
3 Terminal (gọi là Terminal 1,2,3) còn lại sẽ sử dụng để 5 thread con được tạo hiển thị giá trị:
Thread 1, 2 sẽ hiển thị Terminal 1
Thread 3, 4 sẽ hiển thị Terminal 2
Thread 5 sẽ hiển thị Terminal 3 -
Mỗi terminal trong Linux có thể được truy cập qua một đường dẫn file.
Ta có thể lấy đường dẫn của terminal ta đang sử dụng bằng lệnhtty
Giả sử 4 terminal của chúng ta có đường dẫn tương ứng là:
/dev/pts/15
đến/dev/pts/17
-
Ta sẽ sửa lại hàm
PrintHello
ở trên như sau:
const char *TERMINAL_DEV_FILES[] = {
"/dev/pts/19", "/dev/pts/19", "/dev/pts/20", "/dev/pts/20", "/dev/pts/21",
};
void PrintHello(void *threadid) {
FILE *fo = NULL;
long count = 0;
long tid;
tid = (long)threadid;
fo = fopen(TERMINAL_DEV_FILES[tid], "a");
if (fo != NULL) {
count = 0;
while (1) {
fprintf(fo, "Thread %ld : %ldn", tid + 1, ++count);
if (count == 100)
break;
sleep(3);
}
}
fclose(fo);
printf("Bye!!!! Thread #%ld o day !!!n", tid);
pthread_exit(NULL);
}
Giử sử thread chính sẽ được chạy từ một terminal khác.
Kết quả sẽ như sau:
https://youtu.be/Gpy6m8B19qc