71
Th Th c h c h à à nh UNIX/Linux nh UNIX/Linux - - ph ph n 3 n 3 - -

OSLab-3

  • Upload
    le-hang

  • View
    220

  • Download
    0

Embed Size (px)

Citation preview

Page 1: OSLab-3

ThThựực hc hàành UNIX/Linuxnh UNIX/Linux-- phphầần 3 n 3 --

Page 2: OSLab-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)

Page 3: OSLab-3

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

Page 4: OSLab-3

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

Page 5: OSLab-3

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

Page 6: OSLab-3

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.

Page 7: OSLab-3

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

Page 8: OSLab-3

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

Page 9: OSLab-3

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

Page 10: OSLab-3

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

Page 11: OSLab-3

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)

Page 12: OSLab-3

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 !!!

Page 13: OSLab-3

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

Page 14: OSLab-3

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;

}

Page 15: OSLab-3

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

Page 16: OSLab-3

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

Page 17: OSLab-3

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

Page 18: OSLab-3

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

Page 19: OSLab-3

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).

Page 20: OSLab-3

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

Page 21: OSLab-3

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

Page 22: OSLab-3

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

Page 23: OSLab-3

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

Page 24: OSLab-3

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

Page 25: OSLab-3

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…

Page 26: OSLab-3

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)

Page 27: OSLab-3

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

Page 28: OSLab-3

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

Page 29: OSLab-3

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

Page 30: OSLab-3

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$

Page 31: OSLab-3

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()

Page 32: OSLab-3

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

Page 33: OSLab-3

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

Page 34: OSLab-3

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)

Page 35: OSLab-3

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

Page 36: OSLab-3

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

Page 37: OSLab-3

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

}

Page 38: OSLab-3

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

}

Page 39: OSLab-3

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

}

}

Page 40: OSLab-3

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

Page 41: OSLab-3

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

Page 42: OSLab-3

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()

Page 43: OSLab-3

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.

Page 44: OSLab-3

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

Page 45: OSLab-3

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.

Page 46: OSLab-3

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.

Page 47: OSLab-3

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

Page 48: OSLab-3

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

Page 49: OSLab-3

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;

};

Page 50: OSLab-3

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

Page 51: OSLab-3

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

Page 52: OSLab-3

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

}

Page 53: OSLab-3

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

}

}

Page 54: OSLab-3

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

}

Page 55: OSLab-3

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

}

Page 56: OSLab-3

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()

Page 57: OSLab-3

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()

Page 58: OSLab-3

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)

Page 59: OSLab-3

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

Page 60: OSLab-3

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())

Page 61: OSLab-3

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

Page 62: OSLab-3

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

Page 63: OSLab-3

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

Page 64: OSLab-3

ĐĐồồng bng bộộ POSIX threadPOSIX thread(phần tự đọc thêm)

MUTEXES

Conditional variables

POSIX semaphores

Page 65: OSLab-3

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

Page 66: OSLab-3

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ờ)

Page 67: OSLab-3

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

Page 68: OSLab-3

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

Page 69: OSLab-3

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

Page 70: OSLab-3

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.

Page 71: OSLab-3

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