Thực hành Unix, linux: Lập trình trên Linux

Cơ bản về lập trình POSIX pthread „Lập trình IPC dùng signal, pipe, shared memory „Giải quyết tranh chấp bằng SVR4 semaphore „Giải quyết tranh chấp trên POSIX thread (tự đọc thêm)

pdf71 trang | Chia sẻ: haohao89 | Lượt xem: 3365 | Lượt tải: 4download
Bạn đang xem trước 20 trang tài liệu Thực hành Unix, linux: Lập trình trên Linux, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Thực hành UNIX/Linux - phần 3 - 3.2 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình trên Linux (2) „ Cơ bản về lập trình POSIX pthread „ Lập trình IPC dùng signal, pipe, shared memory „ Giải quyết tranh chấp bằng SVR4 semaphore „ Giải quyết tranh chấp trên POSIX thread (tự đọc thêm) „ Tài liệu tham khảo 1. John Shapley Gray: Interprocess Communications in Linux : The Nooks & Crannies, Prentice Hall PTR (2003) 3.3 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Giới thiệu về thread 3.4 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Giới thiệu về thread (t.t) „ Các thread trong cùng một process thì chia sẻ các phần sau z mã (text section) z dữ liệu (data section) z các file descriptors „ Các vùng riêng của mỗi thread z Thread ID z Stack z Thanh ghi 3.5 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Các chuẩn về thread „ POSIX (Portable Operating System Interface) thread hay còn gọi là IEEE 1003.1, 1003.1c z phổ biến trong các hệ thống *NIX hiện tại z đặc tả các giao diện lập trình API và thư viện user-level thread „ Sun Thread 3.6 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình POSIX thread (1) „ Khởi tạo thread mới #include int pthread_create (pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg); „ Kết quả trả về của hàm z Thành công, tạo thread mới: 0, tham số thread chứa thread ID z Thất bại: 0 (mã lỗi trả về chứa trong biến ngoài errno) „ Các tham số z thread: là biến con trỏ kiểu pthread_t, chứa ID của thread mới z attr: chứa các thiết lập thuộc tính cho thread, nếu tham số attr = NULL thì thiết lập theo giá trị mặc định. z start_routine: là tham chiếu đến một hàm của user định nghĩa. Hàm này chứa đoạn mã thực thi cho thread mới. z arg: tham số truyền vào cho hàm start_routine. 3.7 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình POSIX thread (2) „ Lưu ý về tham số thứ 3 start_routine z nên có kiểu trả về là con trỏ kiểu void, nếu không thì phải có type casting khi gọi pthread_create(). z nên có một tham số kiểu con trỏ void. Tham số của hàm start_routine sẽ được truyền vào thông qua tham số thứ 4 của hàm pthread_create(). „ Lưu ý về tham số thứ 4 arg z là tham số truyền vào cho hàm start_routine z nếu cần truyền nhiều hơn 1 tham số thì nên định nghĩa arg là kiểu cấu trúc struct 3.8 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình POSIX thread (3) „ Thread kết thúc thực thi khi z hàm start_routine kết thúc z có lời gọi hàm pthread_exit() tường minh. z thread bị ngắt bởi lời gọi hàm pthread_cancel() z process chính kết thúc z một trong các thread gọi system call exec() „ Lời gọi hàm kết thúc thread tường minh void pthread_exit (void * retval); 3.9 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ về lập trình POSIX thread File thr1.c 1. #include 2. #include 3. void* func(void* arg) 4. { 5. int i; 6. for (i = 0; i < 2; i++) { 7. printf ("This is thread %d\n", *((int*)arg)); 8. sleep (1); 9. } 10.} 11.int main (int argc, char **argv) { 12. int i; 13. pthread_t tid[5]; 14. for (i = 0; i < 5; i++){ 15. pthread_create (&tid[i], NULL, func, (void*)&tid[i]); 16. } 17. sleep (5); 18. return 0; 19.} 3.10 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ về lập trình POSIX thread (t.t) „ Biên dịch và thực thi $gcc thr1.c -o thr1 -lpthread $./thr1 This is thread 1026 This is thread 2051 This is thread 3076 This is thread 4101 This is thread 5126 This is thread 1026 This is thread 2051 This is thread 3076 This is thread 4101 This is thread 5126 chỉ định liên kết với thư viện POSIX pthread 3.11 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ về lập trình POSIX thread (t.t) „ Chú ý quan trọng khi lập trình lập trình POSIX z Phải có chỉ thị #include trong chương trình z Khi biên dịch phải có chỉ định liên kết với thư viện POSIX pthread bằng tùy chọn -lpthread của GCC (một số version GCC mới có thể đã có thiết lập mặc định này nên dù user không chỉ định vẫn biên dịch được) $gcc thr1.c -o thr1 /tmp/cc1PSqgE.o: In function `main': /tmp/cc1PSqgE.o(.text+0x86): undefined reference to `pthread_create' collect2: ld returned 1 exit status z Có thể dùng lệnh ldd để kiểm tra xem file thực thi tạo ra là thr1 phụ thuộc thư viện nào $ldd thr1 libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40028000) libc.so.6 => /lib/i686/libc.so.6 (0x42000000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 3.12 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Các hàm lập trình khác „ PTHREAD_JOIN #include int pthread_join(pthread_t th, void **thread_return); „ Hàm pthread_join() khiến cho thread gọi hàm phải tạm ngưng thực thi, đợi cho đến khi thread có chỉ số thread ID th kết thúc. Tham số thread_return chứa kết quả trả về (chính là giá trị của lệnh return hoặc hàm pthread_exit(…)) „ Nếu thread kia đã kết thúc trước lời gọi hàm -> lỗi (nonzero) „ Nếu có nhiều thread cùng gọi join đến một thread thì cuối cùng chỉ có một thread (?) được báo kết quả chính xác !!! 3.13 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ pthread_join() File thr2.c 1. #include 2. #include 3. void* func(void* arg) 4. { 5. int i; 6. for (i = 0; i < 2; i++) { 7. printf ("This is thread %d\n", *((int*)arg)); 8. sleep (1); 9. } 10. } 11. int main (int argc, char **argv) { 12. int i; 13. pthread_t tid[3]; 14. for (i = 0; i < 3; i++){ 15. pthread_create (&tid[i], NULL, func, (void*)&tid[i]); 16. pthread_join (tid[i], NULL); 17. } 18. return 0; 19. } 3.14 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Truyền dữ liệu cho thread #include #include struct char_print_parms { char character; int count; }; void* char_print (void* args) { struct char_print_parms* p = (struct char_print_parms*) args; int i; for (i = 0; i count; ++i) printf ("%c", p->character); return NULL; } int main () { pthread_t tid; struct char_print_parms th_args; th_args.character = 'X'; th_args.count = 300; pthread_create (&tid, NULL, &char_print, &th_args); pthread_join (tid, NULL); return 0; } 3.15 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Giới thiệu về IPC „ Mục tiêu của IPC z Cho phép phối hợp hoạt động giữa các quá trình trong hệ thống z Giải quyết đụng độ trên vùng tranh chấp z Truyền thông điệp từ quá trình này đến các quá trình khác z Chia sẻ thông tin giữa các quá trình với nhau 3.16 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Giao tiếp và đồng bộ „ Synchronization z Giải quyết tranh chấp z Đảm bảo thứ tự xử lý z Các cơ chế: Lock files Semaphores Mutex (pthread) „ Communication z Truyền dữ liệu z Chia sẻ thông tin z Các cơ chế: Signal Pipes Message queues Shared memory Sockets RPC/RMI 3.17 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Signals „ Dựa vào các sự kiện bất đồng bộ. „ Kernel có nhiệm vụ gửi (deliver) sự kiện đến process „ Các process có thể tự thiết lập các hành vi ứng xử tương ứng với sự kiện nhận được. Signals (events) Process 3.18 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Một số signals thường gặp „ SIGKILL „ SIGSTOP „ SIGHUP „ SIGPIPE „ SIGINT „ SIGQUIT … Tham khảo thêm dùng các lệnh sau $ man signal hoặc info signal $ kill -l $ more /usr/include/bits/signum.h 3.19 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hành vi của process đối với một sự kiện „ Các hành vi có thể thực hiện khi có sự kiện z Thực hiện các hành vi mặc định (do hệ điều hành qui định) TERMINATED/ABORT - kết thúc CORE (Dump) - tạo ra core image (memory dump) và thoát STOP - Trì hoãn thực thi z IGNORE - Bỏ qua signal (ngoại trừ SIGKILL, SIGSTOP) z CATCH - Thực hiện hành vi do người lập trình định nghĩa (signal handler). 3.20 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Các nguồn tạo signal „ Từ kernel z Khi xảy ra một số điều kiện về phần cứng (SIGSEGV, SIGFPE) z Khi xảy ra điều kiện phần mềm (SIGIO) „ Từ user z Tổ hợp phím: Ctrl + C, Ctrl+Z, Ctrl + \ z Khi user dùng lệnh kill „ Từ một process thực hiện system call kill(): #include #include int kill(pid_t pid, int sig); „ Từ lời gọi system call alarm() → tạo ra SIGALARM 3.21 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình với signal #include typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); int sighold(int sig); int sigrelse(int sig); int sigignore(int sig); int sigpause(int sig); 3.22 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lập trình với signal (t.t) sighandler_t signal(int signum, sighandler_t handler); „ Thay đổi hành vi của process đối với signal „ Tham số của hàm signal() z signum: là số hiệu signal mà bạn muốn thay đổi hành vi (trừ SIGKILL hay SIGSTOP) - dạng số hay symbolic z handler: hành vi mới đối với signal, các giá trị có thể là: SIG_DFL: thiết lập lại hành vi về mặc định (default) SIG_IGN: lờ đi (ignore) signal tương ứng Tham chiếu đến hàm xử lý sự kiện (signal-handler) mới do người dùng tự định nghĩa 3.23 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ lập trình với signal „ Bỏ qua signal (sig1.c): #include #include #include #include int main() { int i=0; if (signal(SIGINT, SIG_IGN) == SIG_ERR) { perror("\nSIGINT"); exit(3); } while (1); return 0; } Lưu ý: SIGINT tạo ra khi user nhấn Ctrl+C để kết thúc process đang thực thi Dịch và thực thi: $ gcc sig1.c –o sig1 $./sig1 ^C ^C ^C 3.24 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ lập trình với signal (t.t) „ Định nghĩa hành vi mới đối với tín hiệu SIGINT (sig2.c): #include #include #include #include void newhandler(int sig) { printf("\nI received signal %d", sig); } int main() { int i=0; if (signal(SIGINT, newhandler) == SIG_ERR) { perror("\nSIGINT"); exit(3); } while (1); return 0; } Dịch và thực thi $ gcc sig2.c -o sig2 $ ./sig2 ^C I received signal 2 ^C I received signal 2 ^C I received signal 2 3.25 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Giao tiếp thông qua PIPE „ Là kênh truyền dữ liệu giữa các process với nhau theo dạng FIFO Writer Reader… 3.26 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Các tác vụ trên pipe „ Write: #include ssize_t write (int filedes, const void *buf, size_t count) „ Read: #include ssize_t read (int filedes, const void *buf, size_t count) 3.27 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hai loại pipe z Unnamed pipe có ý nghĩa cục bộ chỉ dành cho các process có quan hệ bố con với nhau z Named pipe (còn gọi là FIFO) có ý nghĩa toàn cục có thể sử dụng cho các process không liên quan bố con 3.28 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Unnamed pipe „ Tạo unnamed pipe: #include int pipe( int filedes[2]); „ Kết quả z Thành công, kết quả thực thi hàm pipe() là 0, có hai file descriptor tương ứng sẽ được trả về trong filedes[0], filedes[1] z Thất bại: hàm pipe() trả về -1, mã lỗi trong biến ngoại errno 3.29 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Unnamed pipe filedes1[1] Æ filedes1[0] filedes2[0] Æ filedes2[1] Process 1 Process 2 „ Duplex z Linux: unidirectional/half-duplex, i.e. filedes[0] chỉ được dùng để đọc còn filedes[1] chỉ được dùng để ghi dữ liệu z Solaris: full-duplex, i.e. nếu ghi vào filedes[0], thì filedes[1] được dùng để đọc và ngược lại 3.30 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ về unnamed pipe #include #include #include #include int main() { int fp[2]; char s1[BUFSIZ]; char s2[BUFSIZ]; pipe(fp); if (fork()==0) { printf("\nInput:"); fgets(s1, BUFSIZ, stdin); s1[strlen(s1)]=0; close(fp[0]); write(fp[1], s1, strlen(s1)+1); } else { close(fp[1]); read(fp[0], s2, BUFSIZ); printf("\nFrom pipe > %s\n", s2); } return 0; } Dịch, thực thi $ gcc pipe.c -o pipe $ ./pipe Input: I Love Penguin From pipe> I Love Penguin $ 3.31 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Dùng pipe để tái định hướng „ Pipe có thể được dùng để kết nối các lệnh với nhau (do chương trình shell thực hiện) z Ví dụ: $ ps -ef | grep a01 | sort $ ls | more „ Đối với chương trình người dùng, có thể dùng một trong hai system call sau kết hợp với pipe để thực hiện: z dup() z dup2() 3.32 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM dup() #include int dup(int filedes); „ Chức năng: tạo bản sao của descriptor filedes. File descriptor nhỏ nhất còn chưa sử dụng sẽ là bản sao của filedes. „ Kết quả của hàm dup() z Thành công: file descriptor bản sao z Lỗi: -1(mã lỗi trong biến ngoại errno) „ File descriptor mới có những thuộc tính chung với file ban đầu z Cùng chỉ đến một file (hay pipe) đang mở z Chia sẻ cùng một file pointer z Có cùng một chế độ truy cập (read, write hoặc read/write) stdin 0 stdout stderror 1 2 3 4 stdin 0 stdout stderror 1 2 3 4 available dup(1); file pointed by file descriptor 1 available 3.33 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM dup2() #include int dup2(int filedes, int filedes2); „ Tương tự dup(), nhưng dup2() cho phép chỉ định file descriptor đích z Descriptor filedes2 trỏ đến cùng một file như filedes stdin 0 stdout stderror 1 2 3 4 stdin 0 stdout stderror 1 2 3 4 dup2(1, 4); file pointed by file descriptor 0 3.34 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Named pipe „ Tương tự như unnamed pipe „ Một số tính năng cần chú ý: z Được ghi nhận trên file system (directory entry, file permission) z Có thể dùng với các process có quan hệ bố con z Có thể tạo ra từ dấu nhắc lệnh shell (bằng lệnh mknod) 3.35 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Tạo unnamed pipe - mknod() System call: #include #include int mknod(const char *path, mode_t mode, dev_t dev); „ Trong đó z path: đường dẫn đến pipe (trên file system) z mode: quyền truy cập trên file = S_IFIFO kết hợp với trị khác z dev: dùng giá trị 0 C/C++ library call #include #include int mkfifo (const char *pathname, mode_t mode); 3.36 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ #include #include #include #include #include extern int errno; #define FIFO1 "/tmp/fifo.1" #define FIFO2 "/tmp/fifo.2" #define PERMS 0666 int main(){ char s1[BUFSIZ], s2[BUFSIZ]; int childpid, readfd, writefd; Dịch & thực thi $gcc fifo.c –o fifo $./fifo Parent inputs string and write to FIFO1:Test1 Child read from FIFO1:Test1 Input string from child to feedback:Test2 Feedback data from FIFO2:Test2 3.37 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ if ( (mknod(FIFO1, S_IFIFO | PERMS, 0) < 0) && (errno !=EEXIST)) { printf("can't create fifo 1: %s", FIFO1); exit(1); } if ( (mknod(FIFO2, S_IFIFO | PERMS, 0) < 0) && (errno !=EEXIST)) { unlink(FIFO1); printf("can't create fifo 2: %s", FIFO2); exit(1); } if ( (childpid = fork()) < 0) { printf("can't fork"); exit(1); } 3.38 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ else if (childpid > 0) { /* parent */ if ((writefd = open(FIFO1, 1)) < 0) perror("parent: can't open write fifo"); if ((readfd = open(FIFO2, 0)) < 0)perror("parent: can't open read fifo"); printf("\nParent inputs string and write to FIFO1:"); gets(s1); s1[strlen(s1)]=0; write(writefd, s1, strlen(s1)+1); read(readfd, s2, BUFSIZ); printf("\nFeedback data from FIFO2:%s\n",s2); while (wait((int *) 0) != childpid); /* wait for child finish */ close(readfd); close(writefd); if (unlink(FIFO1) < 0) perror(“Can't unlink FIFO1”); if (unlink(FIFO2) < 0) perror(“Can't unlink FIFO2”); exit(0); } 3.39 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Ví dụ else { /* child */ if ( (readfd = open(FIFO1, 0)) < 0) perror("child: can't open read fifo"); if ( (writefd = open(FIFO2, 1)) < 0) perror("child: can't open write fifo"); read(readfd, s2, BUFSIZ); printf("\nChild read from FIFO1:%s\n",s2); printf("\nInput string from child to feedback:"); gets(s1); s1[strlen(s1)]=0; write(writefd, s1, strlen(s1)+1); close(readfd); close(writefd); exit(0); } } 3.40 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM SystemV IPC „ Gồm: message queue, shared memory, semaphore „ Có một số thuộc tính chung như z Người tạo, người sở hữu (owner), quyền truy cập (perms) „ Có thể theo dõi trạng thái các IPC bằng lệnh ipcs $ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 644 110592 11 dest ------ Semaphore Arrays -------- key semid owner perms nsems status ------ Message Queues -------- key msqid owner perms used-bytes messages 3.41 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Lệnh IPC trong Linux „ Theo dõi trạng thái các IPC (gồm message queue, semaphore, shared memory) z ipcs hoặc ipcs -a „ Theo dõi trạng thái các semaphore của hệ thống z ipcs -s „ Theo dõi trạng thái các vùng nhớ chia sẻ của hệ thống z ipcs -m „ Loại bỏ một semaphore (phải đủ quyền hạn) z ipcrm sem sem_id hoặc ipcs -s sem_id „ Loại bỏ một vùng nhớ chia sẻ (phải đủ quyền hạn) z ipcrm shm shm_id hoặc ipcs -shm shm_id 3.42 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Các thao tác chủ yếu trên đối tượng IPC „ Tác vụ get z tạo các đối tượng IPC. Ví dụ semget(), shmget() „ Tác vụ điều khiển: z lấy hoặc thay đổi thuộc tính của các đối tượng IPC semctl(), shmctl() „ Specific operations z thay đổi trạng thái hay nội dung của đối tượng IPC nhằm tương tác với quá trình khác. Ví dụ semop() shmat(), shmdt() 3.43 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Semaphore „ Đồng bộ các process theo giải thuật của semaphore „ Biến semaphore z số nguyên, truy cập qua các hàm do hệ điều hành cung cấp: P (wait), V (signal) „ Đảm bảo loại trừ tương hỗ „ Trong UNIX System V, semaphore được dùng theo set – danh sách các semaphore. 3.44 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hàm semget() „ Tạo semaphore: key: giá trị key cho IPC object, nếu key = IPC_PRIVATE thì semaphore tạo ra chỉ được sử dụng trong nội bộ process. nsems: số lượng semaphore trong semaphore set, thông thường chỉ cần dùng 1 semaphore. semflag: IPC_CREAT, IPC_EXCL và có thể OR với giá trị ấn định quyền truy cập (tương tự quyền hạn trên một file). Ví dụ là: sset1_id = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600); sset2_id = semget(12345, 1, IPC_CREAT | IPC_EXCL | 0666); 3.45 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Tạo key cho IPC object „ Mỗi IPC object (là một khối shared memory hoặc một semaphore) được xác định bởi số danh định gọi là key. z Key kiểu là key_t „ Process truy cập một IPC_object thông qua key của đối tượng đó. „ Cách tạo một IPC key dùng hàm ftok() ⇒ các process khác nhau chỉ cần cung cấp path và id giống nhau là có thể tạo đúng key truy cập đến cùng một IPC object. 3.46 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hàm semop() „ Thực hiện các thao tác trên semaphore semid : semaphore set ID do hàm semget() trả về nsops : số semaphores trong semaphore cần thao tác sops : là danh sách gồm nsops cấu trúc sembuf định ra các thao tác cho từng semaphore trong tập semaphore. 3.47 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hàm semop() „ Cấu trúc sembuf struct sembuf { ushort sem_num; /*semaphore #*/ short sem_op; /*operation*/ short sem_flg; /*operation flags*/ } sem_num : chỉ số của semaphore trong semaphore set, chỉ số này bắt đầu từ 0 sem_op : là số nguyên, >0: tăng giá trị semaphore <0: giảm giá trị semaphore sem_flg : IPC_NOWAIT: non-blocking mode SEM_UNDO: undo operation 3.48 Khoa Công nghệ Thông tin - Đại học Bách Khoa Tp. HCM Hành vi
Tài liệu liên quan