Linux C 进程与进程间通信
2016-12-14 14:14
495 查看
Linux C 进程与进程间通信
进程常用API
getpid 获取当前进程IDgetppid 获取当前进程的父进程ID
fork 创建一个进程, 子进程中返回0, 父进程中返回子进程pid.
wait函数族 等待子进程结束, 回收子进程资源.
wait 等待所有子进程结束
waitpid 等待特定子进程结束(也可所有)
exec函数族 执行外部程序, 完全替换当前进程内容, 后缀意义如下.
l: 参数为可变长参数(NULL结尾)
v: 参数为数组
p: 在当前环境变量中搜索
e: 传入环境变量再在其中搜索
execl, execlp, execle
execv, execvp, execve
exit函数族 退出程序
exit 标准库函数, 退出前进行缓冲区清理等操作.
_exit 直接退出, 不做任何处理.
创建进程
进程结束的顺序是不确定的, 用wait来保证子进程先结束.#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { pid_t chi_pid; int ret, chi_stat; chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ printf("child process running, pid: %d, ppid: %d .\n", getpid(), getppid()); sleep(2); printf("child process finished, pid: %d, ppid: %d .\n", getpid(), getppid()); exit(0); } else { /* parent process */ printf("parent process running, pid: %d, ppid: %d .\n", getpid(), getppid()); ret = wait(&chi_stat); if 4000 _error(ret, "wait"); /* wait success */ if (WIFEXITED(chi_stat)) { printf("wait success, status code: %d .\n", WEXITSTATUS(chi_stat)); } /* wait failed */ if (WIFSIGNALED(chi_stat)) { printf("wait failed, status code: %d .\n", WTERMSIG(chi_stat)); } printf("parent process finished, pid: %d, ppid: %d .\n", getpid(), getppid()); } printf("main exit.\n"); return 0; }
僵尸进程
僵尸进程: 已经执行结束, 但是资源还未被回收的进程.利用system函数执行shell脚本, 发现进程状态为Z的僵尸进程.
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define MAXLINE 80 void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { pid_t chi_pid; char shell_cmd[MAXLINE]; chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ exit(0); } else { /* parent process */ sleep(2); } sprintf(shell_cmd, "ps aux | grep %d", chi_pid); system(shell_cmd); printf("main exit.\n"); return 0; }
孤儿进程
孤儿进程: 父进程执行结束, 子进程还在运行的进程.(会被init进程接管)执行结束后查看对应子进程的PPID, 是init进程.
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define MAXLINE 80 void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { pid_t chi_pid; char shell_cmd[MAXLINE]; chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ printf("before parent exit, pid: %d, ppid:%d\n", getpid(), getppid()); sleep(2); printf("after parent exit, pid: %d, ppid:%d\n", getpid(), getppid()); sleep(2); exit(0); } else { /* parent process */ printf("parent exit, child pid: %d .\n", chi_pid); exit(0); } }
两次fork避免僵尸进程
第二次fork产生孙子进程, 让子进程直接结束, 孙子进程变成孤儿进程被init接管.#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { pid_t chi_pid, grand_chi_pid; int ret; chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ grand_chi_pid = fork(); if_error(grand_chi_pid, "fork"); if (grand_chi_pid == 0) { /* grand child process */ sleep(2); printf("grand child process pid: %d, ppid: %d .\n", getpid(), getppid()); exit(0); } else { /* child process */ printf("child process pid: %d, ppid: %d .\n", getpid(), getppid()); exit(0); } } else { /* parent process */ ret = waitpid(chi_pid, NULL, 0); printf("parent process pid: %d, ppid: %d .\n", getpid(), getppid()); } printf("main exit.\n"); return 0; }
exec执行shell命令
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define MAXLINE 80 #define MAXCNT 20 void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } char* cmd_parse(char *buf, char **args) { int cnt = 0; char *cmd; args[cnt++] = cmd = strtok(buf, " "); do { args[cnt] = strtok(NULL, " "); } while (args[cnt++] != NULL); return cmd; } int main(int argc, char **argv) { int chi_pid, ret; char buf[MAXLINE], cmd_exit[MAXLINE]; char *cmd, *args[MAXCNT]; while (1) { chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ printf("input cmd: "); fgets(buf, MAXLINE, stdin); buf[strlen(buf)-1] = '\0'; /* parse cmd */ cmd = cmd_parse(buf, args); ret = execvp(cmd, args); if_error(ret, "execvp"); } else { /* parent process */ chi_pid = wait(NULL); if_error(chi_pid, "wait"); } } return 0; }
进程间通信(IPC)
Linux下的IPC方式有共享内存, 消息队列, 管道, 信号等.共享内存和消息队列需要root权限才能执行
共享内存
shmget 创建/访问 共享内存对象
shmat 把共享内存区对象映射到调用进程的地址空间
shmdt 断开共享内存连接
shmctl 对共享内存提供控制
消息队列
msgget 创建/访问 消息队列
msgrcv 从消息队列中获取消息
msgsnd 把消息添加到消息队列中
msgctl 对消息队列提供控制
管道
pipe 为文件描述符数组建立无名管道
mkfifo 创建命名管道(FIFO)文件
信号
signal 设置信号捕捉句柄
kill 发送信号
共享内存
利用内存进行通信的方式#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/shm.h> #define IPC_KEY 2048 #define MAXLINE 80 #define MAXSIZE MAXLINE*100 void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { pid_t chi_pid; int shm_id, ret; char *shm_ptr; struct shmid_ds shm_stat; char buf[MAXLINE]; char output[MAXSIZE], content[MAXSIZE]; memset(content, 0, sizeof(content)); shm_id = shmget(IPC_KEY, MAXSIZE, IPC_CREAT); if_error(shm_id, "shmget"); shm_ptr = shmat(shm_id, NULL, 0); if_error(*(int*)shm_ptr, "shmat"); chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ printf("input msg:\n"); while (1) { /* input msg */ fgets(buf, MAXLINE, stdin); buf[strlen(buf)-1] = '\0'; /* finish input msg */ if (strncmp(buf, "exit", 4) == 0) break; strcat(content, buf); } /* cp content to shm_ptr */ memcpy(shm_ptr, content, MAXSIZE); } else { /* parent process */ chi_pid = wait(NULL); if_error(chi_pid, "wait"); /* get content from shm_ptr */ memcpy(output, shm_ptr, MAXSIZE); printf("%s\n", output); /* get shm info */ shmctl(shm_id, IPC_STAT, &shm_stat); printf("PID: %d, shared memory size is %ld\n", getpid(), shm_stat.shm_segsz); /* disconnect */ ret = shmdt(shm_ptr); if_error(ret, "shmdt"); } return 0; }
管道
半双工通信无名管道
用于子进程和父进程的简单通信方式#include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #define MAXLINE 80 void if_error(int stat_code, char* err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { int fd[2], ret; pid_t chi_pid; int rd_n, wr_n; char input[MAXLINE], buf[MAXLINE]; /* setup pipe fd[0] read pipe fd[1] write pipe */ ret = pipe(fd); if_error(ret, "pipe"); chi_pid = fork(); if_error(chi_pid, "fork"); if (chi_pid == 0) { /* child process */ close(fd[0]); printf("child process send msg:\n"); while (1) { /* send msg to parent process */ fgets(input, MAXLINE, stdin); input[strlen(input)-1] = '\0'; wr_n = write(fd[1], input, strlen(input)); if_error(wr_n, "read"); /* child process exit */ if (strncmp(input, "exit", 4) == 0) { printf("child process exit .\n"); exit(0); } } } else { /* parent process */ close(fd[1]); while (1) { /* recv msg from child process */ rd_n = read(fd[0], buf, MAXLINE); if_error(rd_n, "read"); buf[rd_n] = '\0'; /* if recv exit msg */ if (strncmp(buf, "exit", 4) == 0) { ret = wait(NULL); if_error(ret, "wait"); printf("parent process exit .\n"); break; } printf("parent process recv msg: %s\n", buf); } } return 0; }
命名管道
用于两个进程间的简单通信read.c
#include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define MAXLINE 80 void if_error(int stat_code, char* err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { int fd, rd_n, ret; char *fifo_path = "./fifo"; char buf[MAXLINE]; /* setup fifo file */ ret = mkfifo(fifo_path, 0664); if (ret < 0 && errno!=EEXIST) return -1; /* open fifo file */ fd = open(fifo_path, O_RDONLY); if_error(fd, "open"); printf("process %d opening FIFO with read-only .\n", getpid()); while (1) { /* read pipe msg */ rd_n = read(fd, buf, MAXLINE); if_error(rd_n, "read"); buf[rd_n] = '\0'; /* recv exit msg */ if (strncmp(buf, "exit", 4) == 0) break; printf("recv pipe msg: %s\n", buf); } printf("read finished\n"); /* remove fifo file */ unlink(fifo_path); close(fd); return 0; }
write.c
#include <unistd.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define MAXLINE 80 void if_error(int stat_code, char* err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int main(int argc, char **argv) { int fd, ret, wr_n; char *fifo_path = "./fifo"; char buf[MAXLINE]; /* setup fifo file */ ret = mkfifo(fifo_path, 0664); if (ret < 0 && errno!=EEXIST) return -1; /* open fifo file */ fd = open(fifo_path, O_WRONLY); if_error(fd, "open"); printf("process %d opening FIFO with write-only .\n", getpid()); while (1) { /* send pipe msg */ printf("send pipe msg:"); fgets(buf, MAXLINE, stdin); buf[strlen(buf)-1] = '\0'; wr_n = write(fd, buf, strlen(buf)); if_error(wr_n, "write"); /* exit msg */ if (strncmp(buf, "exit", 4) == 0) break; } printf("write finished\n"); /* remove fifo file */ unlink(fifo_path); close(fd); return 0; }
消息队列
与命名管道类似的一种通信机制, 可以发送数据块.read.c
#include <unistd.h> #include <sys/msg.h> #include <sys/ipc.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define IPC_KEY 1024 #define MAXLINE 80 void if_error(int stat_code, char* err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } struct msg_ds { char data[MAXLINE]; }; int main(int argc, char **argv) { int msq_id, rd_n; struct msg_ds msg; msq_id = msgget(IPC_KEY, IPC_CREAT); if_error(msq_id, "msgget"); while (1) { /* recv msg */ rd_n = msgrcv(msq_id, (void*)&msg, MAXLINE, 0, 0); if_error(rd_n, "msgrcv"); msg.data[rd_n] = '\0'; /* exit msg */ if (strncmp(msg.data, "exit", 4) == 0) break; printf("recv msg: %s\n", msg.data); } msgctl(msq_id, IPC_RMID, 0); return 0; }
write.c
#include <unistd.h> #include <sys/msg.h> #include <sys/ipc.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define IPC_KEY 1024 #define MAXLINE 80 void if_error(int stat_code, char* err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } struct msg_ds { char data[MAXLINE]; }; int main(int argc, char **argv) { int msq_id, wr_n; struct msg_ds msg; msq_id = msgget(IPC_KEY, IPC_CREAT); if_error(msq_id, "msgget"); while (1) { /* send msg */ printf("send msg: "); fgets(msg.data, MAXLINE, stdin); msg.data[strlen(msg.data)-1] = '\0'; wr_n = msgsnd(msq_id, &msg, MAXLINE, 0); if_error(wr_n, "msgsnd"); /* exit msg */ if (strncmp(msg.data, "exit", 4) == 0) break; } msgctl(msq_id, IPC_RMID, 0); return 0; }
信号
发送信号和捕捉信号的通信方式#include <unistd.h> #include <sys/types.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> void if_error(int stat_code, char *err_msg) { if (stat_code < 0) { perror(err_msg); exit(errno); } } int get_sig = 0; void sig_alarm_handler(int sig) { get_sig = 1; } int main(int argc, char **argv) { pid_t chi_pid; chi_pid = fork(); if_error(chi_pid, "fork"); /* setup signal handler */ signal(SIGALRM, sig_alarm_handler); if (chi_pid == 0) { /* child process */ sleep(5); kill(getppid(), SIGALRM); exit(0); } else { /* parent process */ while (1) { sleep(1); /* check if recv sig */ if (get_sig) { printf("get signal SIGALRM(%d)\n", SIGALRM); break; } else { printf("not get signal\n"); } } } return 0; }
相关文章推荐
- Linux C 文件操作
- yum和编译两种方式升级or降级Centos内核
- yum和编译两种方式升级or降级Centos内核 推荐
- centos6配置网卡
- How to Install PostgreSQL 9.5 on CentOS/RHEL 7/6/5 and Fedora 23/22
- centos7 安装nodejs,git
- linux交互执行命令,expect
- centos 查看文件大小
- Linux_Chrome出现Adobe Flash Player is out of date解决方法
- Linux七种常用技巧
- Linux 关闭和重启的命令
- IBM sever x3650 安装 ubuntu , centos
- linux 下mysql 打开log-bin失败
- Linux常用命令
- Linux系统查看系统是32位还是64位方法总结
- C/C++ linux下光标定位和清屏函数(printf 实现)
- Linux中的sz和rz命令
- Linux下最快速共享目录的方法
- CentOS6.6 php5.6.29 编译安装
- 全平台chrome添加ublock-origin拓展程序