进程
- 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;
}
网友评论