- Back to Home »
- Linux Basic »
- Process và Thread
1. Process & Thread
Process (tiến trình) và Thread (tiểu trình hoặc tuyến) là hai khái niệm rất quan trọng trong lập trình Linux.
Process được định nghĩa là sự thực thi của một chương trình, mỗi process hoạt động trong một không gian vùng nhớ riêng biệt và không xâm phạm lẫn nhau và được định danh bởi số duy nhất PID - Process IDentifier, ngoài ra còn một số chỉ số khác liên quan như UID - User ID, PPID - Parent PID.
Trong mỗi process lại có một hoặc nhiều tác vụ con gọi là Thread (tiểu trình), các thread này sử dụng chung vùng nhớ trong toàn bộ phạm vi của process.
Các process chạy song song với nhau, các thread trong một process cũng chạy song song với nhau. Về bản chất từ "song song" có tính tương đối bởi vì trong thực tế, trong một thời điểm CPU chỉ có thể chạy duy nhất một tác vụ, vì thế mỗi process được phân chia khe thời gian (được lập lịch), mỗi thread trong một process cũng được chia nhỏ khe thời gian ra nữa, nhưng do quá trình này quá nhanh nên đứng dưới góc độ con người chúng ta thấy chúng chạy song song với nhau. Ngoài ra các process/thread có thể được đặt các chế độ ưu tiên khác nhau.
ps
ps -ef
ps -ax
2. Inter-Process Communication (IPC)
IPC khái niệm nói về sự giao tiếp giữa các process với nhau, một số phương pháp sẽ đề cập trong blog này bao gồm
+ Signal
Là cơ chế mà kernel linux phát các sự kiện cho các process, hoặc giữa các process với nhau.
$ top
top - 08:43:54 up 48 min, 2 users, load average: 0.29, 0.25, 0.30
Tasks: 219 total, 1 running, 218 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.8 us, 1.2 sy, 0.0 ni, 97.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 3931812 total, 2726960 used, 1204852 free, 285012 buffers
KiB Swap: 4079612 total, 0 used, 4079612 free, 1054612 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3295 ninhld 20 0 123664 2924 2436 R 4.7 0.1 0:00.10 top
789 dbus 20 0 41928 4016 2744 S 2.4 0.1 0:00.59 dbus-daemon
2020 ninhld 20 0 1624784 189808 90484 S 2.4 4.8 2:18.91 chrome
2142 ninhld 20 0 968196 138264 51104 S 2.4 3.5 0:05.06 chrome
2271 ninhld 20 0 1005448 72260 37600 S 2.4 1.8 3:16.73 chrome
3261 ninhld 20 0 759808 24612 21100 S 2.4 0.6 0:00.27 mate-termi+
1 root 20 0 50904 8340 5480 S 0.0 0.2 0:01.54 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.10 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:+
7 root 20 0 0 0 0 S 0.0 0.0 0:03.73 rcu_sched
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
9 root 20 0 0 0 0 S 0.0 0.0 0:01.96 rcuos/0
10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcuob/0
11 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
12 root rt 0 0 0 0 S 0.0 0.0 0:00.02 watchdog/0
13 root rt 0 0 0 0 S 0.0 0.0 0:00.02 watchdog/1
Ctrl + C
$
+ Pipe
cmd1 | cmd2
Pipe ký hiệu bằng một dấu gạch đứng nếu bạn thao tác tren terminal.
VD:
$ lsmod | grep video uvcvideo 81117 0
video
buf2_vmalloc 13163 1 uvc
video
video
buf2_core 49196 1 uvc
video
video
buf2_memops 13161 1
video
buf2_vmalloc v4l2_common 14542 1
video
buf2_core
video
dev 152475 3 uvc
video
,v4l2_common,
video
buf2_core media 20846 2 uvc
video
,
video
dev
video
19905 1 i915
Lệnh lsmod sẽ liệt kê tất cả các module/driver đã được load (installed) lên kernel linux, tất cả danh sách đó được đưa đến đầu vào của lệnh grep. Lệnh grep thực hiện tìm kiếm xem trong danh sách đưa vào có cái tên nào có chuỗi video hay không.
+ Shared memory
Cả hai process được cấp một không gian bộ nhớ chung, vì thế chúng có thể trao đổi thông tin qua vùng nhớ chung này.
+ Message queue
+ Socket
3. Thread Synchronization
Khác với process hoạt động trong nhưng không gian bộ nhớ riêng biệt, thread lại chia sẻ với nhau không gian bộ nhớ đó, nên một vẫn đề phát sinh là có thể trong một thời điểm nào đó nhiều thread cùng sử dụng chung một vùng nhớ thì sẽ làm kết quả trả về cho thread bị sai.
Ví dụ như tại thời điểm t nào đó, thread A đang ghi giá trị mới cho các biến x,y,z; vì CPU chia khe thời gian cho mỗi thread rất nhanh nên trong khi hoạt động ghi x,y,z chưa xong (mới ghi xong x, còn y, z chưa ghi xong) thì thread A bị dừng lại tạm thời để CPU chạy thread B; công việc của thread B là đọc các giá trị từ biến x,y,z; vì thread A chưa ghi xong nên việc thread B đọc giá trị có thể trả về giá trị cũ chưa được cập nhật (x đúng, y,z sai), cũng tương tụ như thread A thì thread B cũng có thể chưa đọc xong tất cả x,y,z đã phải nhường lại quyền cho thread A.
Vậy có thể thấy, để đảm bảo các thread hoàn thành công việc của mình một cách đúng đắn (thread A ghi xong x,y,z rồi mới chuyển quyền chạy sang cho thread B, tương tự thread B cũng đọc xong x,y,z mới chuyển lại quyền cho thread A) thì Linux cần một cơ chế nào đó làm được yêu cầu như trên.
Dưới đây nêu ra hai cơ chế thông dụng hay được dùng trong lập trình đa tuyến - multi thread
+ Mutex
pthread_mutex_t work_mutex;
int x = 0,y = 0,z = 0;
void *thread_A(void *arg) {
pthread_mutex_lock(&work_mutex);
write x;
write y;
write x;
pthread_mutex_unlock(&work_mutex);
}
void *thread_A(void *arg) {
pthread_mutex_lock(&work_mutex);
read x;
read y;
read x;
pthread_mutex_unlock(&work_mutex);
}
int main() {
create thread A;
create thread B;
return 1;
}
+ Semaphore
sem_t sem_lock;
int x = 0,y = 0,z = 0;
void *thread_A(void *arg) {
sem_wait(&sem_lock);
write x;
write y;
write x;
sem_post(&sem_lock);
}
void *thread_A(void *arg) {
sem_wait(&sem_lock);
read x;
read y;
read x;
sem_post(&sem_lock);
}
int main() {
create thread A;
create thread B;
return 1;
}