Bài giảng Lập trình IPC - Ngô Thanh Nguyên

Lập trình trên Linux
• Lập trình IPC
– Dùng pipe
– Dùng signal
– Dùng semaphore
Lập trình trên Linux
• Lập trình IPC
– Dùng pipe
– Dùng signal
– Dùng semaphore
Giới thiệu về IPC
• Mục tiêu của IPC
– IPC: Inter-Process Communication
– Cho phép phối hợp hoạt động giữa các quá trình
trong hệ thống
– Giải quyết đụng độ trên vùng tranh chấp
– Truyền thông điệp từ quá trình này đến các quá
trình khác
– Chia sẻ thông tin giữa các quá trình với nhau 
pdf 47 trang thiennv 08/11/2022 3180
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình IPC - Ngô Thanh Nguyên", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pdfbai_giang_lap_trinh_ipc_ngo_thanh_nguyen.pdf

Nội dung text: Bài giảng Lập trình IPC - Ngô Thanh Nguyên

  1. Unnamed pipe (2) file des[1] > file des[0] P0 P1 filedes[0] > filedes[1] • Duplex – 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 – Solaris: full-duplex, i.e. nếu ghi vào filedes[0], thì filedes[1] được dùng để đọc và ngược lại Khoa KH&KTMT - ĐH BK Tp.HCM 11
  2. #include Dịch, thựcthi #include $gcc unpipe.c -o #include unpppipe #include $./unpipe int main() { Input: I Love Penguin int fp[2]; From pipe> I Love char s1[BUFSIZ], s2[BUFSIZ]; Penguin pipe(fp); $ if (fork()==0) { /* Child Write */ pritfintf("\nItInput: "); fgets(s1,BUFSIZ,stdin); s1[strlen(s1)]=0; close(fp[])[0]); write(fp[1],s1,strlen(s1)+1); } else { /* Parent Read */ close(fp[1]); read(fp[0],s2,BUFSIZ); printf("\nFrom pppipe> %s\n", s2); } return 0; Khoa KH&KTMT - ĐH BK Tp.HCM 12 }
  3. 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) – 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: – d()dup() – dup2() ps -ef | grep $USER | . . . cmd1 cmd2 . . . cmdN Khoa KH&KTMT - ĐH BK Tp.HCM 13
  4. dup() #include int dup(int oldfd); stdin 0 stdin 0 dup(1) stdout 1 stdout 1 stderr 2 stderr 2 available 3 3 4 available 4 Khoa KH&KTMT - ĐH BK Tp.HCM 14
  5. dup2() #include int dup2(int oldfd, int newfd); stdin 0 stdin 0 dup2(1,4) stdout 1 stdout 1 stderr 2 stderr 2 available 3 available 3 4 4 Khoa KH&KTMT - ĐH BK Tp.HCM 15
  6. #include int main() { // ps -ef | sort | grep int pipe1[2], pipe2[2]; pipe(pipe1); if (fork()) { / * Parent */ pipe(pipe2); if(fork()) { /* Parent */ close(0); // Close standard input dup(pipe2[0]); // standard input -> Read Pipe2 close(pipe1[0]); close(pipe1[1]); close(pipe2[0]); close(pipe2[1]); execl("/bin/grep", "grep", NULL); } Khoa KH&KTMT - ĐH BK Tp.HCM 16
  7. else { /* Child 2 */ close(0); // Close standard input dup(pipe1[0]); // standard input -> Read Pipe1 close(1); // Close standard output dup(pipe2[1]); // standard output -> Write Pipe2 close(pipe1[0]); close(pipe1[1]); close(pipe2[0]); close(pipe2[1]); execl("/bin/sort " , "sort" , NULL); } } else { /* Child 1 */ close(1); // Close standard output dup(pipe1[1]); // standard output -> Write Pipe1 close(pip e1[ 0]); close (pi pe1 [1 ]); execl("/bin/ps", "ps", "-ef", NULL); } exi()it(0); } Khoa KH&KTMT - ĐH BK Tp.HCM 17
  8. Named pipe • Tương tự như unnamed pipe • Một số tính năng cần chú ý: – Được ghi nh ận trê n fil e syst em (di rect ory ent ry, file permission) – Có thể dùng với các process không có quan hệ bố con – Có thể tạo ra từ dấu nhắc lệnh shell (bằng lệnh mknod) Khoa KH&KTMT - ĐH BK Tp.HCM 18
  9. Tạo named pipe - mknod() • System call #include #include int mknod(const char *path, mode_t mode, dev_t dev); • Trong đó – path: đường dẫn đến pipe (trên file system) – mode: quyền truy cập trên file = S_ IFIFO kết hợp với trị khác – dev: dùng giá trị 0 • C/C++ library call #include #include int mkfifo(const char *pathname, mode_t mode); Khoa KH&KTMT - ĐH BK Tp.HCM 19
  10. Dịch và thựcthi $gcc fifo.c -o fifo #include $./fifo #include Parent writes to FIFO1: Test1 #include Child reads from FIFO1: #include Test1 #include Child feedbacks on FIFO2: extern int errno; Test2 Feedback data from FIFO2: Test2 #define FIFO1 "/tmp/fifo.1" #define FIFO2 "/tmp/fifo.2 " #define PERMS 0666 int main(){ char s1[BUFSIZ], s2[BUFSIZ]; int childpid, readfd, writefd; Khoa KH&KTMT - ĐH BK Tp.HCM 20
  11. if ((mknod(FIFO1, S_IFIFO | PERMS, 0)<0) && (errno!=EEXIST)) { printf("can't create fifo1: %s", FIFO1); exit(1); } if ((mknod(FIFO2, S_IFIFO | PERMS, 0)<0) && (errno!= EEXIST)) { unlink(FIFO1); printf("can't create fifo2: %s", FIFO2); exit(1); } if ((childpid=fork())<0) { printf("can't fork"); exit(1); } Khoa KH&KTMT - ĐH BK Tp.HCM 21
  12. else if (childpid>0) { /* parent */ if ((wrifditefd=open(O11)(FIFO1,1))0))<0) perror("parent: can't open writefifo"); if ((readfd=open(FIFO2,0))<0) perror("parent: can't open readfifo"); printf("\nParent writes 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); } Khoa KH&KTMT - ĐH BK Tp.HCM 22
  13. else { /* child */ if ((readfd=open(FIFO1,0))<0) perror("child: can't open readfifo"); if ((writefd=open(FIFO2,1))<0) perror("child: can't open writefifo"); 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); } } Khoa KH&KTMT - ĐH BK Tp.HCM 23
  14. Lập trình trên Linux • Lập trình IPC – Dùng pipe – Dùng signal – Dùng semaphore Khoa KH&KTMT - ĐH BK Tp.HCM 24
  15. 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 Khoa KH&KTMT - ĐH BK Tp.HCM 25
  16. Mộtst số signals thường gặp • SIGKILL • SIGSTOP • SIGPIPE • SIGINT • SIGQUIT • Tham khảo thêm dùng các lệnh sau $7il$ man 7 signal hoặc $if$ info si gnal $ kill -l $$/ more /usr////include/bits/signum.h Khoa KH&KTMT - ĐH BK Tp.HCM 26
  17. Các nguồntn tạo signal • Từ kernel – Khi xảy ra một số điều kiện về phần cứng (SIGSEGV, SIGFPE) – Khi xảy ra điều kiện phần mềm (()SIGIO) • Từ user – Tổ hợp phím: Ctrl+C, Ctrl+Z, Ctrl+\ – Khi user dùng lệnh kill • Từ một process thựchiện system call kill() #include #include int kill(pid_t pid, int sig); • Từ lời gọi system call alarm() → tạo ra SIGALRM Khoa KH&KTMT - ĐH BK Tp.HCM 27
  18. Lậptrìnhvp 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 *t*act, stttruct sitiigaction *oldac t); int sighold(int sig); int sigrelse(int sig); int sigignore(int sig); int sigpause(int sig); Khoa KH&KTMT - ĐH BK Tp.HCM 28
  19. Lậptrìnhvp trình với signal (2) sighandler_ t sigg(nal(int signum, sighandler_ t handler); • Thay đổi hành vi của process đối với signal • Tham số của hàm signal() – 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 – handler: hành vi mới đối với signal, các giá trị có thể là: • SIGSIG_DFL: DFL: thi ếtlt lậplp lạihànhvivi 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 Khoa KH&KTMT - ĐH BK Tp.HCM 29
  20. Lờ đi signal Dịch và thực thi #include $gcc sigign.c –o sigign #include $./sigign #include ^C #in cl ude ^C int main() { ^C if (signal(SIGINT, SIG_IGN)==SIG_ERR) { perror("SIGINT\n"); exit(3); } while (1); return 0; } Khoa KH&KTMT - ĐH BK Tp.HCM 30
  21. Định nghĩa hành vi mới Dịch vàthựcthi #include $gcc sig2.c -o sig2 #inc lu de #include $./sig2 #include ^C void newhandler(int sig) { I received signal 2 printf("\nI received signal %d",sig); ^C } I received signal 2 int main() { ^C int i=0; Iidil2I received signal 2 if (signal(SIGINT,newhandler)==SIG_ERR){ perror("\nSIGINT"); exit(3); } while (1); return 0; } Khoa KH&KTMT - ĐH BK Tp.HCM 31
  22. Lập trình trên Linux • Lập trình IPC – Dùng pipe – Dùng signal – Dùng semaphore Khoa KH&KTMT - ĐH BK Tp.HCM 32
  23. SystemV IPC • Gồm: message queue, shared memory, semaphore • Có một số thuộc tính chung như – 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 shidhmid owner perms bytes nattch status 0x00000000 65536 root 644 110592 11 dest Semaphore Arrays key semid owner perms nsems Message Queues key msqid owner perms used-bytes messages Khoa KH&KTMT - ĐH BK Tp.HCM 33
  24. Semaphore • Đồng bộ các process theo giải thuật của semaphore • Biến semaphore – 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. Khoa KH&KTMT - ĐH BK Tp.HCM 34
  25. Lệnh IPC trong Linux • Theo dõi trạng thái các IPC (gồm message queue, semaphore, shared memory) – ipcs hoặc ipcs -a • Theo dõi trạng thái các semaphore củahệ thống – ipcs -s • Loại bỏ một semaphore (phải đủ quyền hạn) – ipcrm sem semid hoặc ipcrm -s semid Khoa KH&KTMT - ĐH BK Tp.HCM 35
  26. Các thao tác chủ yếu trên đối tượng IPC • semget() • semop() • semctl() Khoa KH&KTMT - ĐH BK Tp.HCM 36
  27. Hàm semget() #include #include #include int semget(key_t key, int nsems, int semflg); ¾ 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ụ sset1=semget(IPC_PRIVATE,1,IPC_CREAT|IPC_EXCL|0600 ); sset2=semget(12345,1,IPC_CREAT|IPC_EXCL|0666); Khoa KH&KTMT - ĐH BK Tp.HCM 37
  28. Tạo key cho IPC object #include #include keyt_t key; char *path; int id=123; key=ftok(path,id); ⇒ 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. Khoa KH&KTMT - ĐH BK Tp.HCM 38
  29. Hàm semop() #include #include #include int semop(int semid, struct sembuf *sops, size_t nsops); – semid: semaphore set ID do hàm semget() trảvề – sops: là danh sách gồm nsops cấu trúc sembuf định ra cáhác thao tá c ch o từng semaphore trong tập semaphore. – nsops: số semaphores trong semaphore cầnthaotác Khoa KH&KTMT - ĐH BK Tp.HCM 39
  30. Cấu trúc sembuf struct sembuf { ushort sem_num; /*semaphore thứ #*/ short sem_op; /*operation*/ short sem_ flg; //p*operation flag g/s*/ } ¾ sem_num: chỉ số của semaphore trong semaphore set, chỉ số này b ắt đầutu 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 Khoa KH&KTMT - ĐH BK Tp.HCM 40
  31. Hành vi c ủa hàm semop() • semop 0 – semval+=semop – SEM_UNDO • semval+=semop AND semadj-=semop Khoa KH&KTMT - ĐH BK Tp.HCM 41
  32. Hàm semctl() #include #inc lu de #include int semctl(int semid,int semnum,int cmd); int semctl(int semid,int semnum,int cmd,union semun arg); union semun{ int val; struct semid_d s*bfbuf; ushort *array; }; Khoa KH&KTMT - ĐH BK Tp.HCM 42
  33. Hàm semctl() - tham số cmd • Các thao tác thông thường – IPC_SET : thiếtlập quyềntruycập – IPC_STAT: lấy thông tin thuộc tính – IPC_ RMID: xoá semaphore set • Các thao tác trên từng semaphore riêng lẻ – GETVAL: lấy thông tin thuộc tính – SETVAL: thay đổiithu thuộc tính – GETPID: lấyPID của process vừatruycập semaphore – GETNCNT: lấy số process đang đợi semval tăng lên – GETZCNT: l ấyys số process đang đợi semval về 0 • Các thao tác trên toàn semaphore set – SETALL: thay đổithuộc tính – GETALL: lấy thông tin thuộc tính Khoa KH&KTMT - ĐH BK Tp.HCM 43
  34. Ví dụ • Hiệnthn thựcc4hàmc 4 hàm cơ bảnnc của semaphore – seminit: tạo binary semaphore – p (wait) – v (signal) – semrel: xoá semaphore • Viết chương trình giải quyết tranh chấp dùng semaphore Khoa KH&KTMT - ĐH BK Tp.HCM 44
  35. #include #include #include #incl ud e #include union { int val; struct semid_ds *buf; ushort *array; } carg; int seminit() { itint i, semid; if (semid=semget(IPC_PRIVATE,1,0666|IPC_EXCL)==-1) return(-1); carg.val=1; if (semctl(semid,0,SETVAL,carg)==-1) return(-1); return semid; } Khoa KH&KTMT - ĐH BK Tp.HCM 45
  36. void p(int sem){ struct sembuf pbuf; pbuf.sem_ num=0; pbuf.sem_op=-1; /* giảm giá trị semaphore */ pbuf.sem_flg=SEM_UNDO; if ( semop(sem,&p bf1)buf,1)==-1) { perror("semop"); exit(1); } } void v(int sem){ struct sembuf vbuf; vbuf.sem_num=0; vbuf.sem_op=1; vbfbuf.sem_ flg=SEM_ UNDO; if (semop(sem,&vbuf,1)==-1) { perror("semop"); exit(1); } } Khoa KH&KTMT - ĐH BK Tp.HCM 46
  37. int semrel(int semid){ return semctl(semid,0,IPC_RMID,0); } void func(int sem) { while(1) { p(sem); /* ent er sec tion */ printf("%d Do something in CS\n",getpid()); sleep(5); v(sem); /* exit section */ printf("%d Out of CS\n",getpid()); sleep(1); } } void main() { int sem=seminit();; if (fork()==0) func(sem); else func(sem); semrel(sem); Khoa KH&KTMT - ĐH BK Tp.HCM 47 }