進程
- fork
進程複製,子進程依賴父進程執行時長
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
pid_t pid;
char *message;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
// pid = 0; 子線程
if (pid == 0) {
// 如果主進程先執行完畢,子進程會提前退出
message = "This is child process \n";
sleep(1);
} else {
message = "This is the parent \n ";
sleep(3);
}
printf("%s\n", message);
return 0;
}
執行應用命令
- execlp
- execvp
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
/**
* execlp(), execvp() 會替代當前進程代碼,執行後直接結束
* p: path
* 第一個參數: 執行文件path
* 第二個參數(s): 代表 argv[0], argv[1]... , 所以第一個argv, 是要和執行文件同名
* 最後一個參數以 NULL 結束
*
*/
int main(void) {
// 知道全部參數的場景下
execlp("/usr/local/bin/oss", "oss", "ls", NULL);
// 以參數數組的形式傳進來
char *cmd = "/usr/local/bin/oss";
char *args[] = {"oss", "ls", NULL};
execvp(cmd, args);
// 正常情況下,不會執行到這裏, 除非上面出錯。
perror("exec error");
exit(1);
}
管道支持
- getchar
- putchar
- toupper
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
/**
* 利用特性:exec結束後,原來的文件fd保持打開狀態
* 利用這個機制,可以編寫管道程序
*/
int main(void) {
int ch;
// EOF : Ctrl-D 退出
while((ch = getchar()) != EOF) {
putchar(toupper(ch));
}
return 0;
}
應用內執行外部文件
- fputs
- dup2
- execl
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
/**
* 把參數文件在程序內部調用 upper 方法
*/
int main(int argc, char *argv[]) {
int fd;
if (argc != 2) {
fputs("usage: wrapper file\n", stderr);
exit(1);
}
// 只讀打開文件
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
// 把外部文件fd, 複製給 標準輸入fd
dup2(fd, STDIN_FILENO);
// 關閉原來的文件fd
close(fd);
// 執行外部應用,它會從標準輸入讀取信息
execl("./upper", "upper", NULL);
perror("exec ./upper");
exit(1);
}
殭屍進程
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
/**
* 錯誤示例:主進程不結束,生成殭屍進程。
* 主進程狀態: ps u 的狀態爲 Z.
* 此時是無法kill -9 的方法殺掉。
*/
int main(void) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid > 0) {
while (1);
}
return 0;
}
進程同步
- waitpid
- getpid
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
int main(void) {
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork failed:");
exit(1);
}
if (pid == 0) {
int i;
for (i = 3; i > 0; i--) {
printf("This is the child\n");
sleep(1);
}
exit(3);
} else {
int stat_val;
// getpid(): 當前進程id
// pid : 子線程id
printf("current pid : %d, child pid : %d\n", getpid(), pid);
// 等待子進程結束
waitpid(pid, &stat_val, 0);
// 如果子進程以 exit()方式結束,獲取其值。
if (WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else if (WIFSIGNALED(stat_val)) // 以中斷等方式退出的,走進這裏
printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
}
return 0;
}
進程同信-IPC
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#define MAXLINE 80
/**
* 進程間通信: IPC (InterProcess Communication)
* pipe(fd[2]) 創建一個管道, fd[0]: 讀端, fd[1]: 寫端
*/
int main(void) {
ssize_t n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0) {
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid > 0) { /* 主進程 */
/**
* 主進程只管寫,所以先關閉 讀端 ?
*/
close(fd[0]);
char *msg = "hello world\n";
write(fd[1], msg, strlen(msg));
// 寫入寫端後,等待子進程結束
wait(NULL);
} else { /* 子進程 */
/**
* 先關閉寫端
*/
close(fd[1]);
// 從讀端讀取一行
n = read(fd[0], line, MAXLINE);
// 打印到標準輸出
write(STDOUT_FILENO, line, n);
}
return 0;
}