Tạo mới tiến trình với exec
in Programming on C++, Process, Linux
Để thực hiện được điều này chúng ta sẽ sử dụng kết hợp giữa fork()
và một hàm mới đó là exec(…)
.
Hàm exec
là một họ các hàm có chức năng thay thế ảnh của tiến trình hiện tại bằng ảnh của tiến trình mới. Chắc hẳng bạn đã từng xem film matrix rồi nhỉ, anh boss có khả năng nhập vào một người bất kỳ và biến người đó thành mình, chà, nghe có vẻ nguy hiểm. Hàm exec
cũng có “khả năng” tương tự như boss, nó có thể biến chương trình đang chạy hiện tại thành một chương trình khác theo nghĩa đen. Với exec
, ta có khá nhiều “version” để lựa chọn như sau:
- int execl(const char *path, const char *arg, …);
- int execlp(const char *file, const char *arg, …);
- int execle(const char path, const char *arg, …, char const envp[]);
- int execv(const char *path, char *const argv[]);
- int execvp(const char *file, char *const argv[]);
- int execvpe(const char *file, char *const argv[], char *const envp[]);
Nhìn thì nhiều và hoa mắt nhưng thực ra thì cũng chỉ cung cấp cho người dùng các sự lựa chọn như: Thực thi từ file(bạn có thể truyền tên chương trình) hoặc từ đường dẩn, truyền danh sách đối số bởi một mảng hay truyền kiểu “tôi thích bao nhiêu tôi pass bấy nhiêu”, hay định nghĩa các biến môi trường cho chương trình mới.
Hàm exec
chỉ trả về khi có lỗi xảy ra, chú ý nhé. Đoạn này thì cũng dể hiểu vì khi hàm exec
thành công, nó sẽ thay thế chương trình cũ bằng chương trình mới(ngay tiến trình hiện tại gọi nó). Vì thế nên các lênh dưới hàm exec
sẽ bị thay thế bởi những lệnh khác.
Dưới đây là đoạn code mẫu sử dụng hàm fork kết hợp với execvp
(một trong các hàm exec
) để chạy một chương trình khác từ tiến trình con mới được tạo ra.
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
// create a child process then execute new program instead | |
// of duplicating caller process(default by fork() function). | |
pid_t spawn(const char * program, char * const * args) | |
{ | |
// create new child process by call fork() | |
pid_t child_pid = fork(); | |
// check if current calling process is parent process | |
// so we just return pid | |
if (child_pid != 0) | |
{ | |
return child_pid; | |
} | |
else | |
{ | |
// caller is child process, then we replace current image | |
// byte new image which declared by program variant | |
execvp(program, args); | |
// when current image has been replaced by new image, so this | |
// statement from here will be replaced by new commands which | |
// defined in new image | |
fprintf(stderr, "Error occurred in execvp."); | |
abort(); | |
} | |
} | |
int main() | |
{ | |
// initializing arguments for new program which created in child process, | |
// by convention, the first argument should be program file name, and lastest | |
// argument must be NULL pointer | |
char * args[] = {"ls", "-l", NULL}; | |
pid_t child_pid = spawn("ls", args); | |
printf("Main program created child program with pid is %d\n", child_pid); | |
return 0; | |
} |
Kết quả như sau:
Bạn chú ý rằng danh sách đối số được pass cho chương trình mới bởi hàm exec
có một quy ước như sau: Đối số đầu tiên nên là tên file của chương trình mới mà chúng ta muốn chạy trong child process, các đối số khác phải là một null-terminated string(là mảng char, hay một xâu kết thúc bởi NULL
), đối số cuối cùng của danh sách các đối số phải là NULL
.
Nếu chương trình của bạn không cần đối số gì thì cũng phải định nghĩa tối thiểu như sau:
char * args[] = {"filename.exe", NULL};