Saturday, June 6, 2015

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.


Trong Linux cung cấp sẵn một số lệnh trên terminal để show ra danh sách các process

 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.


Một ví dụ đơn giản bạn chạy lệnh "top" trên terminal, lệnh này có tác dụng hiển thị trạng thái tài nguyên CPU đang chạy theo thời gian thực (giống task manager trong windows), lệnh này sẽ liên tục chạy mà không tự động kết thúc, muốn kết thúc bạn dùng tổ hợp phím Ctrl  + C, thao tác này sẽ gửi đến process của lệnh "top" một signal có tên SIGINT - Terminal interrupt yêu cầu kết thúc ngay process.

 $ 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
Cơ chế đường ống cho phép dữ liệu đầu ra của process này sẽ được chuyển đến đầu vào của process kia.

 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   
 videobuf2_vmalloc   13163 1 uvcvideo  
 videobuf2_core     49196 1 uvcvideo  
 videobuf2_memops    13161 1 videobuf2_vmalloc  
 v4l2_common      14542 1 videobuf2_core  
 videodev       152475 3 uvcvideo,v4l2_common,videobuf2_core  
 media         20846 2 uvcvideo,videodev  
 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
Trao đổi qua các bản tin



+ Socket
Socket là cơ chế thông dụng nhất thường được dùng để liên lạc giữa các process, chúng có là phương tiện liên lạc giữa hai process cùng nằm trên tầng application (user space), giữa process trên user space với process dưới kernel space và giữa hai process chạy trên hai thiết bị vật lý khác nhau.
Socket là việc liên lạc thông qua các gói packet, liên kết được thiết lập theo cơ chế client - server.




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;  
 }  



Leave a Reply

Subscribe to Posts | Subscribe to Comments

- Copyright © Lập trình hệ thống nhúng Linux . Powered by Luong Duy Ninh -