Upload
le-hang
View
220
Download
0
Embed Size (px)
Citation preview
ThThựực hc hàành UNIX/Linuxnh UNIX/Linux-- phphầần 3 n 3 --
3.2Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình trên Linux (2)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ảo1. John Shapley Gray: Interprocess Communications in Linux : The
Nooks & Crannies, Prentice Hall PTR (2003)
3.3Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
GiGiớới thii thiệệu vu vềề thread thread
3.4Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
GiGiớới thii thiệệu vu vềề thread (t.t)thread (t.t)
Các thread trong cùng một process thì chia sẻ các phần saumã (text section)
dữ liệu (data section)
các file descriptors
Các vùng riêng của mỗi threadThread ID
Stack
Thanh ghi
3.5Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác chuc chuẩẩn vn vềề threadthread
POSIX (Portable Operating System Interface) thread hay còn gọi là IEEE 1003.1, 1003.1c
phổ biến trong các hệ thống *NIX hiện tại
đặc tả các giao diện lập trình API và thư viện user-level thread
Sun Thread
3.6Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình POSIX thread (1)nh POSIX thread (1)
Khởi tạo thread mới#include <pthread.h>int pthread_create (pthread_t * thread, pthread_attr_t * attr,
void * (*start_routine)(void *), void * arg);
Kết quả trả về của hàmThành công, tạo thread mới: 0, tham số thread chứa thread IDThất bại: <> 0 (mã lỗi trả về chứa trong biến ngoài errno)
Các tham sốthread: là biến con trỏ kiểu pthread_t, chứa ID của thread mới 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.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.arg: tham số truyền vào cho hàm start_routine.
3.7Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình POSIX thread (2)nh POSIX thread (2)
Lưu ý về tham số thứ 3 start_routinenê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().
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 arglà tham số truyền vào cho hàm start_routine
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.8Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình POSIX thread (3)nh POSIX thread (3)
Thread kết thúc thực thi khihàm start_routine kết thúc
có lời gọi hàm pthread_exit() tường minh.
thread bị ngắt bởi lời gọi hàm pthread_cancel()
process chính kết thúc
một trong các thread gọi system call exec()
Lời gọi hàm kết thúc thread tường minhvoid pthread_exit (void * retval);
3.9Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ vvềề llậập trp trìình POSIX threadnh POSIX threadFile thr1.c
1. #include <pthread.h>2. #include <stdio.h>
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.10Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ vvềề llậập trp trìình POSIX thread (t.t)nh POSIX thread (t.t)
Biên dịch và thực thi$gcc thr1.c -o thr1 -lpthread$./thr1This is thread 1026This is thread 2051This is thread 3076This is thread 4101This is thread 5126This is thread 1026This is thread 2051This is thread 3076This is thread 4101This is thread 5126
chỉ định liên kết với thư viện POSIX pthread
3.11Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ vvềề llậập trp trìình POSIX thread (t.t)nh POSIX thread (t.t)
Chú ý quan trọng khi lập trình lập trình POSIX Phải có chỉ thị #include <pthread.h> trong chương trình
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
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.12Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác hc hààm lm lậập trp trìình khnh kháácc
PTHREAD_JOIN#include <pthread.h>
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.13Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ pthread_join()pthread_join()File thr2.c
1. #include <pthread.h>2. #include <stdio.h>
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.14Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
TruyTruyềền dn dữữ liliệệu cho threadu cho thread#include <pthread.h>#include <stdio.h>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 < p->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.15Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
GiGiớới thii thiệệu vu vềề IPCIPC
Mục tiêu của IPCCho phép phối hợp hoạt động giữa các quá trình trong hệ thốngGiải quyết đụng độ trên vùng tranh chấpTruyền thông điệp từ quá trình này đến các quátrình khácChia sẻ thông tin giữa các quá trình với nhau
3.16Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Giao tiGiao tiếếpp vvàà đ đồồng bng bộộ
SynchronizationGiải quyết tranh chấpĐảm bảo thứ tự xử lýCác cơ chế:
Lock filesSemaphoresMutex (pthread)
CommunicationTruyền dữ liệu
Chia sẻ thông tin
Các cơ chế:
Signal
Pipes
Message queues
Shared memory
Sockets
RPC/RMI
3.17Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
SignalsSignals
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.18Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
MMộột st sốố signals thư signals thườờng gng gặặpp
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.19Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
HHàành vi cnh vi củủa process đa process đốối vi vớới mi mộột st sựự kikiệệnn
Các hành vi có thể thực hiện khi có sự kiệnThực hiện các hành vi mặc định (do hệ điều hành qui định)
TERMINATED/ABORT - kết thúcCORE (Dump) - tạo ra core image (memory dump) vàthoátSTOP - Trì hoãn thực thi
IGNORE - Bỏ qua signal (ngoại trừ SIGKILL, SIGSTOP)CATCH - Thực hiện hành vi do người lập trình định nghĩa (signal handler).
3.20Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác nguc nguồồn tn tạạoo signalsignal
Từ kernelKhi 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ừ userTổ hợp phím: Ctrl + C, Ctrl+Z, Ctrl + \Khi user dùng lệnh kill
Từ một process thực hiện system call kill():#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);
Từ lời gọi system call alarm() → tạo ra SIGALARM
3.21Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình vnh vớới signali signal
#include <signal.h>
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.22Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLậập trp trìình vnh vớới signal (t.t)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()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à:
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.23Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ llậập trp trìình vnh vớới signali signal
Bỏ qua signal (sig1.c):#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>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.24Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ llậập trp trìình vnh vớới signal (t.t)i signal (t.t)
Định nghĩa hành vi mới đối với tín hiệu SIGINT (sig2.c):#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>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.25Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Giao tiGiao tiếếp thông qua PIPEp 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.26Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác tc táác vc vụụ trên pipetrên pipe
Write:#include <unistd.h>
ssize_t write (int filedes, const void *buf, size_t count)
Read:#include <unistd.h>
ssize_t read (int filedes, const void *buf, size_t count)
3.27Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Hai loHai loạại pipei pipe
Unnamed pipe
có ý nghĩa cục bộ
chỉ dành cho các process có quan hệ bố con với nhau
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.28Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Unnamed pipeUnnamed pipe
Tạo unnamed pipe:
#include <unistd.h>
int pipe( int filedes[2]);
Kết quả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]
Thất bại: hàm pipe() trả về -1, mã lỗi trong biến ngoại errno
3.29Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Unnamed pipeUnnamed pipe
filedes1[1] filedes1[0]
filedes2[0] filedes2[1]
Process 1 Process 2
DuplexLinux: 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
3.30Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ vvềề unnamed pipeunnamed pipe#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>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.31Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
DDùùng pipe đng pipe đểể ttáái đi địịnh hưnh hướớngng
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:
dup()
dup2()
3.32Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
dup()dup()
#include <unistd.h>
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()
Thành công: file descriptor bản saoLỗ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 đầuCùng chỉ đến một file (hay pipe) đang mởChia sẻ cùng một file pointerCó cùng một chế độ truy cập (read, write hoặc read/write)
stdin 0stdoutstderror
1234
stdin 0stdoutstderror
1234
available
dup(1);
file pointed by file descriptor 1
available
3.33Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
dup2()dup2()
#include <unistd.h>
int dup2(int filedes, int filedes2);
Tương tự dup(), nhưng dup2() cho phép chỉ định file descriptor đích
Descriptor filedes2 trỏ đến cùng một file như filedes
stdin 0stdoutstderror
1234
stdin 0stdoutstderror
1234
dup2(1, 4);
file pointed by file descriptor 0
3.34Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Named pipeNamed pipe
Tương tự như unnamed pipe
Một số tính năng cần chú ý:
Được ghi nhận trên file system (directory entry, file permission)
Có thể dùng với các process có quan hệ bố con
Có thể tạo ra từ dấu nhắc lệnh shell (bằng lệnh mknod)
3.35Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
TTạạo unnamed pipe o unnamed pipe -- mknodmknod()()
System call:#include <sys/types.h>#include <sys/stat.h>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ácdev: dùng giá trị 0
C/C++ library call#include <sys/types.h>
#include <sys/stat.h>
int mkfifo (const char *pathname, mode_t mode);
3.36Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ
#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/errno.h>extern int errno;
#define FIFO1 "/tmp/fifo.1"#define FIFO2 "/tmp/fifo.2"#define PERMS 0666int main(){
char s1[BUFSIZ], s2[BUFSIZ];int childpid, readfd, writefd;
Dịch & thực thi$gcc fifo.c –o fifo$./fifoParent 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.37Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ
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.38Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ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.39Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ
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.40Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
SystemV IPC 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 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.41Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
LLệệnh IPC trong Linux 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ủa hệ thốngipcs -s
Theo dõi trạng thái các vùng nhớ chia sẻ của hệ thốngipcs -m
Loại bỏ một semaphore (phải đủ quyền hạn)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)ipcrm shm shm_id hoặc ipcs -shm shm_id
3.42Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác thao tc thao táác chc chủủ yyếếu trên đu trên đốối tưi tượợng IPCng IPC
Tác vụ gettạo các đối tượng IPC. Ví dụ
semget(), shmget()
Tác vụ điều khiển: lấy hoặc thay đổi thuộc tính của các đối tượng IPC
semctl(), shmctl()
Specific operationsthay đổ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.43Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
SemaphoreSemaphore
Đồng bộ các process theo giải thuật của semaphore
Biến semaphoresố 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.44Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
HHààm semgetm 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.45Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
TTạạo key cho IPC objecto 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.
Key kiểu là key_tProcess 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.46Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
HHààm semopm 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.47Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
HHààm semopm semop()()
Cấu trúc sembufstruct 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ừ 0sem_op : là số nguyên,
>0: tăng giá trị semaphore<0: giảm giá trị semaphore
sem_flg : IPC_NOWAIT: non-blocking modeSEM_UNDO: undo operation
3.48Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
HHàành vi cnh vi củủa ha hààm semop()m semop()
semval ≥ abs(semop): semval=semval-abs(semop)
semval ≥ abs(semop) & SEM_UNDO:
semval-=abs(semop) AND semadj+=abs(semop)
semval<abs(semop): block until semval ≥ abs(semop)
semval<abs(semop) & IPC_NOWAIT: return -1, errno=EAGAIN
3.49Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
semctlsemctl()()
Thực hiện các tác vụ thay đổi trạng thái semaphore:#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 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_ds *buf;ushort *array;
};
3.50Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
semctl() semctl() -- tham stham sốố cmdcmd
Các thao tác thông thường:IPC_SET : thiết lập quyền truy cậpIPC_STAT: lấy thông tin thuộc tínhIPC_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ínhSETVAL: thay đổi thuộc tínhGETPID: lấy PID của process vừa truy cập semaphoreGETNCNT: lấy số process đang đợi semval tăng lênGETZCNT: lấy số process đang đợi semval về 0
Các thao tác trên toàn semaphore set:SETALL: thay đổi thuộc tínhGETALL: lấy thông tin thuộc tính
3.51Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ
Hiện thực 4 hàm cơ bản của semaphoreseminit: 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
3.52Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ ((semasema.h) .h) #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
union {
int val;
struct semid_ds *buf;
ushort *array;
} carg;
int seminit(int val) {
int i, semid;
semid=semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
if (semid==-1) return(-1);
carg.val=1;
if (semctl(semid, val, SETVAL, carg)==-1) return(-1);
return (semid);
}
3.53Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ ((semasema.h).h)
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, &pbuf, 1)== -1) {
perror("semop");
exit(1);
}
}
3.54Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ ((semasema.h).h)void v(int sem) {
struct sembuf vbuf;
vbuf.sem_num=0;
vbuf.sem_op=1;
vbuf.sem_flg=SEM_UNDO;
if (semop(sem, &vbuf, 1)== -1) {
perror("semop");
exit(1);
}
}
int semrel (int semid) {
return (semctl(semid, 0,IPC_RMID, 0));
}
3.55Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ (sema.c(sema.c))void func(int sem) {
while(1) {
p(sem); /* enter section */
printf("%dDo s.t. in CS\n",getpid());
sleep(5);
v(sem); /* exit section */
printf("\n%d Out of CS\n",getpid());
sleep(1);
}
}
void main() {
int sem;
sem=seminit(0);
if(fork()==0) {
func(sem);
}
else func(sem);
}
3.56Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Shared memoryShared memory
Cho phép nhiều process dùng chung một vùng bộ nhớKích thước tối thiểu/tối đa của vùng là 1byte/4MB
Số vùng nhớ chia sẻ tối đa trong toàn hệ thống: 4096
Cách sử dụngVùng nhớ chia sẻ phải được tạo ra trước bằng shmget()
Process phải gắn (attached) vùng nhớ chia sẻ vào không gian địa chỉ của mình bằng hàm shmat() trước khi sử dụng.
Sau khi dùng xong có thể gỡ (detached) vùng nhớ chia sẻra khỏi không gian địa chỉ của process bằng hàm shmdt()
3.57Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Shared memoryShared memory
System call shmget() shmat() and shmdt()shmctl()
3.58Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
shmgetshmget()()
Tạo một shared memory#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget (key_t key, int size, int shmflg);
key: key tương ứng với shared memory
size: kích thước (tính theo đơn vị byte)
shmflg: tương tự như semflg của semget(), nhưng không cóIPC_EXCL
Ví dụ: shm_id = shmget(123, 4096, IPC_CREAT | 0660)
3.59Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
shmatshmat()()
Gắn shared memory vào address space của process#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> void *shmat(int shmid, void *shmaddr, int shmflg);
shmid: shared memory ID trả về từ hàm shmget().shmaddr: địa chỉ nơi gắn vùng nhớ chia sẻ, nếu bằng NULL thìhệ điều hành tự chọn.shmflg: SHM_RDONLY (read-only) hoặc không
Kết quả trả về:- Thành công: địa chỉ nơi gắn vùng nhớ chia sẻ trong không
gian địa chỉ của process- Thất bại: NULL
3.60Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
shmdtshmdt()()
Gỡ shared memory khỏi không gian địa chỉ của process#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt (void *shmaddr);
shmaddr: địa chỉ nơi gắn vùng nhớ chia sẻm (chính là kết quả trả về từ hàm shmat())
3.61Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
shmctlshmctl()()
Lấy thông tin và thay đổi thuộc tính#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl (int shmid, int cmd, struct shmid_ds *buf);
shmid: shared memory ID trả về từ hàm shmget().cmd: IPC_STAT, IPC_SET and IPC_RMID
3.62Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ
Dịch và thực thi$gcc shm.c –o shm$./shmProcess 28216 write to shared mem ...$Process 28217 read:Sum=1110
Tạo shared memory 128 bytes
Hai process dùng chung shared memory
Process thứ nhất ghi 2 integer vào shared memory
Process thứ hai đọc từ shared meomory và ghi tổng hai số vào shared memory
Process thứ nhất đọc tổng và hiển thị ra
3.63Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
VVíí ddụụ#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdio.h>int main() {
int *shm, shmid, k;shmid=shmget(IPC_PRIVATE, 128, IPC_CREAT|0666);shm = (int *) shmat(shmid,0,0);if(fork()==0) { /*child*/
shm[0]=111;shm[1]=999;sleep(3);pintf("\nProcess %d read:Sum=%d", getpid(), shm[2]);shmdt((void *)shm);shmctl(shmid, IPC_RMID, (struct shmid_ds *)0);
}else { /*parent*/sleep(1);printf("Process %d write to shared mem ...\n", getpid());shm[2]=shm[0]+shm[1];shmdt((void *)shm);}
return(0);}
ĐĐồồng bng bộộ POSIX threadPOSIX thread(phần tự đọc thêm)
MUTEXES
Conditional variables
POSIX semaphores
3.65Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
MUTEXESMUTEXES
Tương tự semaphore, MUTEX cung cấp cách thức loại trừ tương hỗ (mutual exclusion) giữa các pthread
Sử dụng MUTEX#include <pthread.h>
Khai báo biến MUTEX (kiểu của biến là pthread_mutex_t)
pthread_mutex_t mutex;
Khởi động trị ban đầu cho biến MUTEX. Ví dụ
mutex = PTHREAD_MUTEX_INITIALIZER; /* fast mutex */
mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; /* recursive mutex */
Cũng có thể khởi động bằng hàm
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
3.66Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Thay đThay đổổi thui thuộộc tc tíính binh biếến MUTEXn MUTEX
Dùng hàm pthread_mutex_init() #include <pthread.h>
int pthread_mutexattr_init( pthread_mutexattr_t *attr );
Trong đótypedef struct {
int __mutexkind;
} pthread_mutexattr_t;
Các giá trị có thể có của __mutexkind và ý nghĩaPTHREAD_MUTEX_FAST: là fast mutex, i.e. nếu mutex bị khóa lần hai bởi chính owner (là thread khóa lần đầu) của mutex thì deadlock, còn nếu gọi lệnh khóa là thread khác thì thread đó bị blocked.
PTHREAD_MUTEX_RECURSIVE: recursive mutex, cho phép khóa nhiều lần, mutex chỉ unlock khi số lần gọi tháo khóa = số lần gọi mở khóa :)
PTHREAD_MUTEX_ERRORCHECK: nếu một thread thực hiện tác vụ khóa trên biến mutex đã khóa thì sẽ trả về lỗi (không deadlock và không chờ)
3.67Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
ĐĐồồng bng bộộ pthreadpthread
Khóa và tháo khóa trên MUTEX int pthread_mutex_lock( pthread_mutex_t *mutex );
>> thread gọi hàm sẽ bị block nếu mutex đã bị khóa
int pthread_mutex_unlock( pthread_mutex_t *mutex );
Thử khóa int pthread_mutex_trylock( pthread_mutex_t *mutex );
thread gọi hàm không bị block nếu mutex đã bị khóa như đối với gọi pthread_mutex_lock()
Hủy khóa int pthread_mutex_destroy( pthread_mutex_t *mutex );
3.68Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
Conditional variablesConditional variables
Conditional variables (biến điều kiện)hoạt động theo cơ chế wait-signal, cho phép một hoặc nhiều thread chờ một sự kiện nào đó phát sinh, khi có sự kiện thì các thread đang chờ sẽ được kích hoạt để thực thiPhải dùng kèm với mutex
Khai báo và khởi động #include <pthread.h>
Khai báo biến điều kiện (kiểu của biến là pthread_cond_t)pthread_cond_t dk;
Khởi động trị ban đầu cho biến. Ví dụdk = PTHREAD_COND_INITIALIZER;
Cũng có thể khởi động biến điều kiện bằng hàm int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t
*cond_attr);
3.69Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác thao tc thao táác trên bic trên biếến đin điềều kiu kiệện n
Thao tác #include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
chọn một thread đang chờ trên sự kiện cond để kích hoạt thực thi
int pthread_cond_broadcast(pthread_cond_t *cond);
kích hoạt thực thi tất cả thread đang chờ trên sự kiện cond
int pthread_cond_destroy(pthread_cond_t *cond);
hủy biến điều kiện cond
3.70Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
CCáác thao tc thao táác trên bic trên biếến đin điềều kiu kiệện n
Thao tác #include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
thread gọi hàm phải chờ trên sự kiện cond và bị blocked. Biến mutex phải được khóa trước khi gọi hàm này. Ví dụ
pthread_mutex_lock(&lock_it);
…
pthread_cond_wait(&write_it, &lock_it);
…
pthread_mutex_unlock(&lock_it);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
tương tự pthread_cond_wait() nhưng có cho phép chỉ định timeout.
3.71Khoa Công nghKhoa Công nghệệ Thông tin Thông tin -- Đ Đạại hi họọc Bc Báách Khoa Tp. HCMch Khoa Tp. HCM
POSIX semaphorePOSIX semaphore
Tương tự UNIX SystemV semaphore, nhưng cách sử dụng đơn giản hơn và chỉ dùng cho pthread
#include <semaphore.h>
Khởi độngint sem_init(sem_t *sem, int pshared, unsigned int value);
Sử dụngint sem_wait(sem_t * sem);
int sem_trywait(sem_t * sem);
int sem_post(sem_t * sem);
Hủyint sem_destroy(sem_t * sem);