24
Tìm hiểu về Process Người tạo: Ngô Nguyn Chính Ngày tạo: 2013/08/02

Tìm hiểu về process

Embed Size (px)

Citation preview

Page 1: Tìm hiểu về process

Tìm hiểu về Process

Người tạo: Ngô Nguyễn Chính

Ngày tạo: 2013/08/02

Page 2: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 2/27

NỘI DUNG

1 TÌM HIỂU VỂ TIẾN TRÌNH (PROCESS)................................................................... 3

1.1 Tiến trình là gì ............................................................................................................... 3

1.2 Trạng thái tiến trình ...................................................................................................... 3

1.3 Khối điều khiển tiển trình (Process Control Block-PCB) .............................................. 4

1.4 Thao tác trên tiến trình ................................................................................................. 5

1.4.1 Tạo tiến trình ........................................................................................................................... 5

1.4.2 Kết thúc tiến trình .................................................................................................................... 6

1.4.3 Orphan Process....................................................................................................................... 6

1.4.4 Zombie Process....................................................................................................................... 6

1.5 Giao tiếp liên tiến trình (Inter Process Communication – IPC)..................................... 7

2 HÀM FORK .............................................................................................................. 8

3 HÀM CREATEPROCESS ...................................................................................... 13

4 MỘT SỐ BÀI TOÁN PORTING TỪ LINUX SANG WINDOWS VÀ SOLUTION...... 21

4.1 Porting fork() ............................................................................................................... 21

5 TÀI LIỆU THAM KHẢO .......................................................................................... 27

Page 3: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 3/27

1 TÌM HIỂU VỂ TIẾN TRÌNH (PROCESS)

1.1 Tiến trình là gì

- Tiến trình: là một chương trình đang trong thời gian thực hiện.

- Bộ nhớ tiến trình (process memory) được chia thành 4 phân vùng như sau:

o Text: chứa mã chương trình được compile

o Data: lưu các biến global và static

o Heap: được sử dụng cho cấp phát bộ nhớ động và được quản lí thông qua gọi các hàm new, delete, free, malloc...

o Stack: được sử dụng cho các biến local, không gian trên stack được dành riêng cho các biến local khi chúng được khai báo và không gian được giải phóng khi biến đi ra khỏi phạm vi. Chú ý, stack cũng được sử dụng cho giá trị trả về của hàm.

- Khi các tiến trình được swap ra ngoài memory và sau đó được phục hồi, các thông tin bổ sung cũng phải được store và restore thông qua sử dụng PC (program counter), các thanh ghi.

1.2 Trạng thái tiến trình

- Mỗi tiến trình có thể ở một trong các trạng thái sau:

o New: Tiến trình được tạo ra.

o Ready: Tiến trình có tất cả các resource mà nó cần chạy, nhưng CPU hiện tại không làm việc trên các instruction của tiến trình này.

o Running: CPU đang làm việc trên các instruction của tiến trình

o Waiting: Tại thời điểm này tiến trình không thể chạy. Nó đang chờ một số resource thành available hay một sự kiện nào đó xuất hiện. Ví dụ:

Đợi đầu vào từ bàn phím, inter-process message hay tiến trình con kết thúc...

Page 4: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 4/27

o Terminated: Tiến trình hoàn thành việc thực thi

1.3 Khối điều khiển tiển trình (Process Control Block-PCB)

- Mỗi tiến trình có 1 PCB. Nó chứa các thông tin riêng của tiến trình (process-specific information).

o Trạng thái tiến trình (process state): Các trạng thái có thể là New, Running,...

o Các thanh ghi CPU và bộ đếm chương trình (Program counter - PC): Được sử dụng để store hay restore khi swap in/out tiến trình.

Program counter: Bộ đếm hiển thị instruction kế tiếp được thực thi cho tiến trình này

o Số nguyên định danh tiến trình (process id – pid) và số nguyên định danh tiến trình cha (parent process id – ppid).

(*)Trong Win32, không hỗ trợ API để lấy được ppid của tiến trình.

Page 5: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 5/27

- Lưu đồ hiển thị việc chuyển CPU từ quá trình này tới quá trình khác

1.4 Thao tác trên tiến trình

1.4.1 Tạo tiến trình

- Các tiến trình có thể tạo ra các tiến trình khác thông qua lời gọi hệ thống (system call), chẳng hạn

như fork, spawn, CreateProcess.

- Tiến trình gọi (calling process) là tiến trình cha (parent process), tiến trình mới được được tạo là tiến trình con của tiến trình đó.

- Có 2 tùy chọn cho tiến trình cha sau khi tạo ra tiến trình mới: (1) Tiến trình cha tiếp tục thực thi, đồng thời với việc thực thi của tiến trình con. (2) Tiến trình cha đợi cho tới khi tiến trình con của nó kết thúc

- Cũng có 2 khả năng cho không gian địa chỉ của tiến trình con: (1) Tiến trình con là bản sao của tiến trình cha.

Mỗi tiến trình sẽ có 1 PCB riêng, bao gồm: PC, các thanh ghi, và pid. Đây là đặc tính của hàm fork trên Linux/Unix.

(2) Tiến trình con có 1 chương trình mới được nạp vào không gian địa chỉ của nó.

Đây là đặc tính của hàm spawn trên Windows. Trong Linux/Unix, thực hiện điều này giống bước thứ 2, sử dụng hàm exec (bước 1 là gọi hàm fork).

Page 6: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 6/27

1.4.2 Kết thúc tiến trình

- Các tiến trình có thể yêu cầu kết thúc chính nó bằng cách gọi hàm exit(). (*) Trong Linux/Unix, khi tiến trình con kết thúc, nó thường trả về exitCode. exitCode này được truyền tới tiến trình cha nếu tiến trình cha đang wait().

(1) Nếu exitCode là 0: tiến trình con kết thúc Normal (2) Nếu exitCode khác 0: tiến trình con kết thúc Abnormal

- Các tiến trình có thể kết thúc bởi hệ thống với 1 số các lí do sau: (1) Hệ thống không có khả năng cung cấp resource cần thiết (2) Tiến trình cha có thể kill tất cả các tiến trình con của nó nếu công việc được gán với tiến trình

con là không cần thiết (3) Nếu tiến trình cha kết thúc , hệ điều hành có thể có hoặc không cho phép tiến trình con tiếp

tục nếu tiến trình cha kết thúc.

- Khi kết thúc tiến trình, tất cả resource của hệ thống được giải phóng, các file được flush và đóng…

Trong Linux/Unix, trạng thái kết thúc tiến trình và thời gian thực thi được truyền tới tiến trình cha

nếu tiến trình cha đang đợi tiến trình con kết thúc, hoặc được truyền tới init process nếu tiến trình trở

thành orphan [1.4.3]

1.4.3 Orphan Process

- Trong Linux/Unix, nếu tiến trình cha kết thúc trước tiến trình con của nó, tiến trình con tự động được nhận là “con nuôi” (adopt child) của tiến trình init (pid = 1)

1.4.4 Zombie Process

Trong Linux/Unix:

- Một tiến trình kết thúc không thể rời khỏi hệ thống cho đến khi tiến trình cha của nó chấp nhận mã trả về của nó (exit code).

- Nếu tiến trình cha của nó thật sự “chết” , tiến trình con sẽ được nhận “làm con nuôi” của tiến trình “init”, tiến trình init này luôn luôn chấp nhận mã trả về của các tiến trình con của nó

- Nếu tiến trình cha còn tồn tại (alive) nhưng không bao giờ thực thi wait(), mã trả về của tiến trình con sẽ không bao giờ được chấp nhận => tiến trình con sẽ trở thành một Zombie.

- Một zombie process không có code, data, stack và heap, do vậy, nó không sử dụng nhiều resource

của hệ thống.

Tuy nhiên, nó vẫn tồn tại trong task list của hệ thống.

Page 7: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 7/27

1.5 Giao tiếp liên tiến trình (Inter Process Communication – IPC)

- Các tiến trình thực thi trên hệ thống có thể là các tiến trình độc lập (Independent Processes ) hay các tiến trình hợp tác (Cooperating Processes).

- Một tiến trình là độc lập nếu nó không thể ảnh hưởng hay bị ảnh hưởng bởi các tiến trình khác thực thi trong hệ thống.

- Một tiến trình là hợp tác nếu nó có thể ảnh hưởng hay bị ảnh hưởng bởi các tiến trình khác trong hệ thống. Có 1 số lí do tại sao sử dụng hợp tác tiến trình:

(1) Information sharing (Chia sẻ thông tin): Thí dụ trường hợp, nhiều tiến trình cùng truy xuất 1

file (như pipelines)

(2) Computation speedup (Gia tăng tốc độ tính toán): Một tác vụ có thể chạy nhanh hơn, nếu tác vụ đó có thể chia thành nhiều tác vụ nhỏ, các tác vụ này được thực hiện đồng thời.

(3) Modularity (Tính module hóa): Chia hệ thống thành các module tương tác, chia các chức năng thành các tiến trình (process) hay các luồng (thread).

(4) Convenience (Tính tiện dụng): User có thể thực hiện multi-task tại cùng 1 thời điểm

- Các tiến trình hợp tác sử dụng 1 số phương thức giao tiếp liên tiến trình. Hai loại phổ biến nhất:

(1) Share memory: Đây là 1 phương thức trao đổi dữ liệu giữa các chương trình đang chạy cùng

một lúc. Một tiến trình sẽ tạo 1 vùng nhớ trên RAM cho phép các tiến trình khác có thể truy

nhập

(2) Message-passing: Các tiến trình có thể gửi hoặc nhận message tới các tiến trình khác.

(3) Ngoài ra, còn các phương thức IPC khác: File, Signal, Socket, Message Queue, Pipe, Semaphore…

Page 8: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 8/27

2 HÀM FORK

- Trong Linux/Unix, lời gọi hệ thống fork() được sử dụng để tạo tiến trình mới.

- Tiến trình mới (new process) được tạo ra là tiến trình con

- Tiến trình gọi (calling process) là tiến trình cha

- Tiến trình con gần như là 1 bản sao chính xác của tiến trình cha. Hệ điều hành thực hiện copy bộ nhớ tiến trình cha (code, data, heap, và stack), các thanh ghi, open files... và đưa nó vào tiến trình con.

- Tuy nhiên, tiến trình con và tiến trình cha có các số pid (process id) và ppid (parent process id) khác nhau.

- Giá trị trả về của hàm fork()

(1) Nếu phát sinh lỗi: Nó trả về -1 cho tiến trình cha và không có tiến trình con được tạo ra

(2) Nếu thành công:

Trả về PID của tiến trình con được tạo mới cho tiến trình cha

Trả về 0 cho tiến trình con

Page 9: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 9/27

- Một số ví dụ:

(1) Ví dụ 1: Khi tiến trình con trở thành orphan, thì PPID của nó được gán là 1 (tiến trình init trở

thành tiến trình cha của nó)

/** * File fk_orphan.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <stdio.h> #include <sys/types.h> #include <unistd.h>

int main(int ac, char* av[]) {

pid_t childpid;

/* create process */ childpid = fork();

if (childpid < 0) {

printf("fork() failed! \n"); } else if (childpid == 0) {

printf("Child process, getpid() = %d, getppid() = %d\n", getpid(), getppid());

} else {

}

sleep(5); printf("After sleeping: Child process, getpid() = %d, getppid() = %d\n",

getpid(), getppid());

printf("Parent process exiting now!\n");

return 0; }

Kết quả:

$ ./fk_orphan

Child process, getpid() = 7807, getppid() = 7806

Parent process exiting now!

$ After sleeping: Child process, getpid()

= 7807, getppid() = 1

Page 10: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 10/27

(2) Ví dụ 2: Minh họa không gian địa chỉ của tiến trình cha được copy tới tiến trình con

/** * File fk_duplicate.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <stdio.h> #include <sys/types.h> #include <unistd.h>

int K; int main(int ac, char* av[]) {

pid_t childpid; int j;

j = 200; K = 300;

printf("Before forking, j = %d, K = %d\n", j, K); /* create process */ childpid = fork();

if (childpid < 0) {

printf("fork() failed! \n"); } else if (childpid == 0) {

j++; K++; printf("After forking, child process, j = %d, K = %d\n", j, K);

} else /* Delay parent process */ {

sleep(1); printf("After forking, parent process, j = %d, K = %d\n", j, K);

} return 0;

}

Nhận xét:

Sau khi fork(), mỗi tiến trình có vùng nhớ cho j và K. Vì vậy, khi tiến trình con thay đổi

giá trị của j là 201 và K là 300, nó chỉ ảnh hưởng đến các giá trị j và K của nó, không ảnh

hưởng gì tới giá trị j và K của tiến trình cha.

Kết quả:

(1) Chuyển hướng output tới terminal:

$ ./fk_duplicate

Before forking, j = 200, K = 300

After forking, child process, j = 201, K = 301

After forking, parent process, j = 200, K = 300

(2) Chuyển hướng output tới 1 file:

$ ./fk_duplicate > output $ cat output

Before forking, j = 200, K = 300

After forking, child process, j = 201, K = 301

Page 11: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 11/27

Before forking, j = 200, K = 300

After forking, parent process, j = 200, K = 300

Phân tích lí do sai khác: Khi chuyển hướng output tới terminal, stdout là 1 line buffered, do vậy, khi thực hiện fputc(„\n‟) hoặc tương đương, buffer được ghi tới standard output với “write(1,...)”

Khi stdout chuyển hướng tới 1 file, trường hợp này stdio library cung cấp 1 bufferring là

Fully buffered, nó không ghi cho đến khi buffer là full. (4K hay 8K characters). Do vậy, tại

thời điểm fork() gọi, chuỗi kí tự “Before forking:” không được ghi tới fd=1. Thay vào đó, nó

được buffer trong standard I/O library. Buffer là 1 phần không gian địa chỉ, do đó, nó được

copy tới tiến trình con khi fork() được gọi => “Before forking:” được viết tới file 2 lần.

(*) Buffering:

Mục đích của cung cấp bufferring bởi standard I/O library là để tối thiểu số lần gọi read() và

write().

Có 3 loại buffering:

(1) Fully buffered: I/O chỉ được thực hiện khi standard I/O buffer được fill. Các tệp

tin năm trên ổ được thường được fully buffered

(2) Line buffered: standard I/O library thực hiện I/O khi 1 dòng kí tự mới được đưa

tới input hoặc output. Standard input và standard output là các ví dụ.

(3) Unbuffered: Standard I/O library không buffer các kí tự. Nếu ghi 15 kí tự với hàm

fputs, chúng ta trông đợi 15 kí tự được output sớm nhất có thể. Điều này có thể

thực hiện với hàm write().

(3) Ví dụ 3: Minh họa cho tất cả open file descriptor được duplicate.

/** * File fk_descriptor.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h>

#define BUFFERSIZE 1000

int main(int ac, char* av[]) {

pid_t childpid; int seekp; int fd; char s1[BUFFERSIZE] = {0}; char s2[BUFFERSIZE] = {0};

fd = open("tmpfile", O_WRONLY | O_TRUNC | O_CREAT, 0666);

strcpy(s1, "Before forking\n"); write(fd, s1, strlen(s1));

/* create process */ childpid = fork();

if (childpid < 0) {

printf("fork() failed! \n"); }

Page 12: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 12/27

else if (childpid == 0) {

strcpy(s1, "Child process"); } else /* Delay parent process */ {

sleep(1); strcpy(s1, "Parent process");

} seekp = lseek(fd, 0, SEEK_CUR); sprintf(s2, "%s: After forking - Seeking pointer = %d\n", s1, seekp); write(fd, s2, strlen(s2)); return 0;

}

File được open cho việc ghi trong chương trình trên, nó được open cho cả tiến trình cha và

tiến trình con.Chú ý, tập tin mở của 2 tiến trình là như nhau, khi 1 tiến trình ghi vào cuối file,

con trỏ seek được thay đổi trong cả tiến trình cha và con.

Kết quả:

$ ./fk_descriptor

$ cat tmpfile Before forking

Child process: After forking: Seeking pointer = 15

Parent process: After forking: Seeking pointer = 66

Page 13: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 13/27

3 HÀM CREATEPROCESS

- Trong Windows, CreateProcess tạo ra 1 tiến trình mới và 1 primary thread cho tiến trình đó.

(*) Trong Windows, các process được thực thi giống như các objects.

- Tiến trình được tạo mới là tiến trình con. Tiến trình gọi (calling process) là tiến trình cha.

- Flow của CreateProcess như sau:

Như flow trên ta thấy, CreateProcess có thể return tới caller process trước khi tiến trình mới thật sự

được khởi tạo đầy đủ. Nếu trong tiến trình mới này có thực hiện load dll mà các dll này bị load thất

bại thì process sẽ bị hủy nhưng hàm CreateProcess vẫn trả về TRUE.

- Cú pháp:

Page 14: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 14/27

- Giá trị trả về của hàm:

(1) TRUE: Hàm success

(2) FALSE: Hàm fail

- Tham số:

(1) lpApplicationName: Tên của module được thực thi. Tham số này hay được để NULL, thay vào đó sử dụng lpCommandLine để chỉ thị process nào được thực thi.

(2) lpCommandLine : Dòng lệnh được thực thi

Sử dụng đường dẫn tương tự như trong command line để cho biết process nào sẽ được thực

thi.

Nếu tên file thực thi không có phần mở rộng, .EXE sẽ được gán.

Nếu tên file thực thi không chứa đường dẫn thư mục, hệ thống search file thực thi theo tuần

tự sau:

(1) Trong thư mục ứng dụng được load

(2) Thư mục hiện tại cho tiến trình cha

(3) Trong thư mục System/System32

(4) Trong thư mục Windows

(5) Trong các thư mục được list trong biến môi trường PATH

(3) LpProcessAttributes: Con trỏ tới cấu trúc SECURITY_ATTRIBUTES, quyết định xem

handle trả về cho process object mới có thể được kế thừa bởi các tiến trình con. Nếu

LpProcessAttributes là NULL, handle không thể được kế thừa.

(4) lpThreadAttributes : Con trỏ tới cấu trúc SECURITY_ATTRIBUTES, quyết định xem handle

trả về cho thread object mới có thể được kế thừa bởi các tiến trình con. Nếu

lpThreadAttributes là NULL, handle không thể được kế thừa.

(5) bInheritHandles: Nếu tham số này là TRUE, mỗi handle có thể kế thừa trong calling process

được kế thừa trong tiến trình mới. Nếu tham số này là FALSE, các handle không được kế

thừa. Chú ý rằng, các handle có cùng giá trị và quyên truy cập như handle ban đầu.

(6) dwCreationFlags : Cờ cho phép chỉ định độ ưu tiên (priority class) của tiến trình và tạo tiến trình theo cách thực nào.

Page 15: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 15/27

Danh sách các giá trị Process Creation Flags.

Constant/value Description

CREATE_NEW_CONSOLE Tạo cửa sổ console mới cho tiến trình mới,

thay vì thừa kế console của tiến trình cha

(default). Cờ này không được sử dụng với

DETACHED_PROCESS

CREATE_NO_WINDOW Tiến trình là 1 ứng dụng console,nhưng

được chạy mà không có console window.

Console handle cho ứng dụng không được

set. Cờ này được bỏ qua nếu ứng dụng

không phải là ứng dụng console.

CREATE_NEW_PROCESS_GROUP Tiến trình mới là tiến trình root của 1

nhóm tiến trình mới. Group tiến trình bao

gồm tất cả các tiến trình là “hậu duệ” của

tiến trình root. ProcessID của nhóm tiến

trình mới cũng giống với PID, được trả về

trong lpProcessInformation.

Group tiến trình được sử dụng bởi

GenerateConsoleCtrlEvent để enable gửi 1

tín hiệu CTRL+BREAK tới nhóm các tiến

trình console. Nếu cờ này được lựa chọn,

tín hiệu CTRL+C sẽ được disable tới tất cả

các process trong nhóm tiến trình mới.

Cờ này bị bỏ qua nếu sử dụng

CREATE_NEW_CONSOLE

CREATE_SUSPENDED Primary thread của tiến trình mới được tạo

trong trạng thái suspend. Và không chạy

cho đến khi ResumeThread được gọi

Danh sách các giá trị GetPriorityClass

Priority Class Flag Identifier

Idle IDLE_PRIORITY_CLASS

Below normal BELOW_NORMAL_PRIORITY_CLASS

Normal NORMAL_PRIORITY_CLASS

Above normal ABOVE_NORMAL_PRIORITY_CLASS

High HIGH_PRIORITY_CLASS

Realtime REALTIME_PRIORITY_CLASS

Gía trị mặc định NORMAL_PRIORITY_CLASS

Page 16: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 16/27

(7) lpEnvironment :

Một con trỏ tới block environment của tiến trình mới. Nếu là NULL, tiến trình mới sử dụng

environment của tiến trình gọi

(8) lpCurrentDirectory : Đường dẫn đầy đủ tới thư mục cho tiến trình.

Nếu tham số này là NULL, tiến trình con sẽ có current drive và thư mục giống với tiến trình

gọi

(9) lpStartupInfo : Một con trỏ tới STARTUPINFO struct

(10) lpProcessInformation : Một con trỏ tới PROCESS_INFORMATION structure để

nhận thông tin xác định cho tiến trình mới.

Handle trong PROCESS_INFORMATION struct phải được đóng với CloseHandle khi

không còn cần thiết.

- Tính kế thừa (Inheritance):

Tiến trình con có thể kế thừa các tính chất và resource từ tiến trình cha. Các resource dưới đây có thể

được kế thừa:

(1) Các open handle được trả về bởi hàm CreateFile(). Bao gồm các handle tới các file, console input buffers, console screen buffers, ...

(2) Các open handle tới process, thread, mutex, semaphore objects...

(3) Các biến môi trường

(4) Thư mục hiện tại (current directory)

(5) Console

- Một số ví dụ:

(1) Ví dụ 1: Chương trình thực thi lệnh sử dụng CreateProcess()

/** * File crtp_execCmd.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <windows.h> #include <stdio.h>

/* Declare functions */ int execCmd(char*, int);

int main(int ac, char* av[]) {

/* execute mspaint.exe */ execCmd("mspaint", TRUE); return 0;

}

Page 17: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 17/27

/* * execCmd: execute command line */

int execCmd (char *cmd, BOOL waitFlag) {

int rtn; /* return value of funtion*/ STARTUPINFOA sui; /* startup information */ PROCESS_INFORMATION pi; /* process information */ BOOL bRet; /* return code */ DWORD dwExitCode; /* exit code */ int iAt;

/* initialize return value of funtion */ rtn = 0; /* initialize exit code */ dwExitCode = 0;

/* setup startupinfo parameters */ sui.cb = sizeof( STARTUPINFO ); /* size of the structure */ sui.lpReserved = 0; /* reserved */ sui.lpDesktop = NULL; /* desktop name (reserved) */ sui.lpTitle = NULL; /* window title */ sui.dwX = 0; /* X position of the window */ sui.dwY = 0; /* Y position of the window */ sui.dwXSize = 0; /* X window size */ sui.dwYSize = 0; /* Y window size */ sui.dwXCountChars = 0; /* screen buffer width */ sui.dwYCountChars = 0; /* screen buffer height */ sui.dwFillAttribute = 0; /* text and background color */ sui.dwFlags = STARTF_USESHOWWINDOW ; /* flags */ sui.wShowWindow = SW_SHOWNORMAL;/* ShowWindow - 0 (SW_HIDE), 1 (SW_SHOWNORMAL) */

sui.cbReserved2 = 0; /* Reserved */ sui.lpReserved2 = NULL; /* Reserved */

/* Create process */ bRet = CreateProcessA( NULL, /* pointer to name of executable module */

cmd, /* pointer to command line string */ NULL, /* pointer to process security attributes */ NULL, /* pointer to thread security attributes */ FALSE, /* handle inheritance flag */ 0, /* creation flags */ NULL, /* pointer to new environment block */ NULL, /* pointer to current directory name */ &sui, /* pointer to STARTUPINFO */ &pi ); /* pointer to PROCESS_INFORMATIO */

if (bRet) {

if( waitFlag ) { /* wait for the child process */ WaitForSingleObject(pi.hProcess, INFINITE);

iAt = 0; dwExitCode = STILL_ACTIVE; while (dwExitCode == STILL_ACTIVE && iAt < 60) {

GetExitCodeThread(pi.hThread, &dwExitCode); Sleep(1); iAt++;

}

if (dwExitCode != 0) { rtn = -1;

printf("execCmd: %s [Error]GetLastError() = %x\n", cmd, GetLastError());

}

Page 18: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 18/27

}

}

else {

}

/* Close process and thread handles */ CloseHandle( pi.hProcess ); CloseHandle( pi.hThread );

printf("CreateProcess() failed: %x\n", GetLastError()); rtn = -1;

return( rtn ); }

(2) Ví dụ 2: Minh họa tiến trình con thừa kế handle file từ tiến trình cha

(1) Parent: /** * File crtp_ParentPog.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <windows.h> #include <stdio.h> #include <stdlib.h>

HANDLE g_hFile;

int main(int ac, char* av) {

STARTUPINFOA sui; /* startup information */ PROCESS_INFORMATION pi; /* process information */ BOOL bRet; /* return code */ char s[100] = {0}; SECURITY_ATTRIBUTES sa; int iAt; DWORD dwExitCode = 0;

/* Setup security attributes */ sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; /* To allow inheritance of file handle */

/* Create a file handle */ g_hFile = CreateFileA("crtp_ParentProg.c",

GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if (g_hFile == INVALID_HANDLE_VALUE) { printf("CreateFile failed: %x\n", GetLastError());

}

/* Init a startup structure */ GetStartupInfoA(&sui); /* For console process, lpTitle: NULL - the name of executable file is used as the window title instead */ sui.lpTitle = NULL;

Page 19: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 19/27

/* convert the g_hFile handle to a string */ _itoa((DWORD)g_hFile, s, 10);

/* Create the child process */ bRet = CreateProcessA ("crtp_ChildProg.exe",

s, 0, 0, TRUE, /* To allow inherit of file handle */ CREATE_NEW_CONSOLE, 0, 0, &sui, &pi);

if (!bRet) { printf("CreateProcess failed: %x\n", GetLastError());

}

/* wait for the child process */ WaitForSingleObject(pi.hProcess, INFINITE);

iAt = 0; dwExitCode = STILL_ACTIVE; while (dwExitCode == STILL_ACTIVE && iAt < 60) {

GetExitCodeThread(pi.hThread, &dwExitCode); Sleep(1); iAt++;

}

if (dwExitCode != 0) { printf("[Error] GetLastError() = %x\n", GetLastError());

}

/* Close process and thread handles */ CloseHandle( pi.hProcess ); CloseHandle( pi.hThread );

return 0; }

(2) Child: /** * File crtp_ChildPog.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <windows.h> #include <stdio.h> #include <stdlib.h>

#define BUFFERSIZE 200

HANDLE g_hFile;

int main(int ac, char *av[]) {

char ReadBuffer[BUFFERSIZE] = {0}; DWORD dwNumRead; BOOL bRet;

Page 20: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 20/27

/* Get handle value of the command line */ g_hFile = (HANDLE) atoi(av[0]);

/* Using file handle to read the file */ bRet = ReadFile(g_hFile,

ReadBuffer, 100, &dwNumRead, 0);

if (!bRet) { printf("ReadFile failed: %x\n", GetLastError());

} /* Output the string */ if (dwNumRead > 0 && dwNumRead <= BUFFERSIZE-1) {

ReadBuffer[dwNumRead] = '\0'; } printf("%s\n", ReadBuffer);

Sleep(2000); return 0;

}

Kết quả:

Page 21: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 21/27

4 MỘT SỐ BÀI TOÁN PORTING TỪ LINUX SANG WINDOWS

4.1 Porting fork()

Bài toán: Làm thế nào porting hàm fork() để mã nguồn có thể chạy được trên Windows đúng xử lí logic

Phân tích:

- Hàm fork() tạo ra 1 tiến trình con là bản sao của tiến trình cha

- Sau khi tiến trình con được tạo ra, thường có 2 khả năng:

(1) Tiến trình cha thực thi đồng thời với tiến trình con

(2) Tiến trình cha đợi cho đến khi tiến trình con hoàn thành, tiến trình cha mới tiếp tục thực thi

Tùy từng trường hợp để đưa ra giải pháp thay thế hợp lí

Giải pháp:

(1) Tiến trình cha thực thi đồng thời với tiến trình con

Ví dụ minh họa sau:

/** * File fk_forkConcurrent.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h>

int g_nProcId;

int main(int ac, char* av[]) {

int rtn; /* return value */ int pid;

/* init return code */ rtn = 0; /* create process */ switch (pid = fork()) { case -1:

printf("Create process failed! \n"); rtn = -1; break;

case 0: (void)execlp("/home/chinhnguyen/Desktop/fork/subApp", "subApp", NULL);

default: printf("Parent process: child pid = %d\n", pid); g_nProcId = pid; rtn = 0; break;

} return rtn;

}

Page 22: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 22/27

Kết quả:

$ ./fk_forkConcurrent

Parent process: child pid = 13887

$ ps -e

PID TTY TIME CMD

1 ? 00:00:01 init

2 ? 00:00:00 kthreadd

3 ? 00:00:00 migration/0

...

7792 pts/1 00:00:15 gedit

13282 pts/2 00:00:00 bash

13887 pts/0 00:00:00 subApp

13890 pts/2 00:00:00 ps

Phân tích:

Xử lí logic của chương trình trên như sau:

Sau khi gọi fork(), tiến trình cha tiếp tục thực thi mà không wait() giá trị exitCode trả về từ tiến trình

con.

Tiến trình con được tạo ra là bản sao tiến trình cha.

Trong xử lí của tiến trình con, hàm execlp() được gọi. Tiến trình con bị replace với 1 process image

mới.

Với sự thay thế process image này, tiến trình con có 1 chương trình mới được nạp vào, giống như

CreateProcess() hay spawn() trên Windows

Cách giải quyết sử dụng CreateProcess:

/** * File crtp_CreateProcessConcurrent.c * Author Ngo Nguyen Chinh * Date 2013.08.08 */

#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <errno.h>

int g_nProcId;;

int main(int ac, char* av) {

int rtn; /* return value */

STARTUPINFOA sui; /* startup information */ PROCESS_INFORMATION pi; /* process information */ BOOL bRet; /* return code */

Page 23: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 23/27

/* init return code */ rtn = 0;

/* Setup startup information */ sui.cb = sizeof(STARTUPINFO);

sui.lpDesktop = "";

sui.dwFlags = STARTF_USESHOWWINDOW;

sui.wShowWindow = SW_SHOWDEFAULT; /* create process */ bRet = CreateProcessA(NULL,

"subApp.exe", NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sui, &pi);

if (!bRet) { printf("Create process failed! \n"); rtn = -1;

} else {

}

printf("Parent process: child pid = %d\n", pi.dwProcessId); g_nProcId = pi.dwProcessId; rtn = 0;

return rtn; }

(2) Tiến trình cha đợi cho đến khi tiến trình con hoàn thành

Phân tích tương tự như trên để đưa ra solution.

Page 24: Tìm hiểu về process

Tìm hiểu về Process 2013/08/02

Created by Ngô Nguyễn Chính 24/27

5 TÀI LIỆU THAM KHẢO

[1] Giáo trình hệ điều hành – TS.Phạm Văn Tiến

[2] http://linux.die.net/man/

[3] http://msdn.microsoft.com

[4] http://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/3_Processes.html

[5] http://web.eecs.utk.edu/~huangj/cs360/360/notes/Fork/lecture.html

[6]Linux for Programers and Users – Graham Glass, King Ables