#include <stdio.h> #include <unistd.h> int gval = 10; int main() { pid_t pid; int lval = 20; gval++, lval += 5; pid = fork(); //子进程 if (pid == 0) { gval += 2, lval += 2; } else { gval -= 2, lval -= 2; } //子进程 if (pid == 0) { printf("子进程[%d,%d]\n", gval, lval); } else { sleep(30); printf("父进程[%d,%d]\n", gval, lval); } printf("猜猜我是啥[%d,%d]\n", gval, lval); }
fork函数子进程返回0, 父进程返回子进程的 pid
#include <sys/wait.h> pid_t wait(int * statloc); 成功时返回终止的子进程ID, 失败时返回 -1
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid; int status; pid = fork(); //子进程 if (pid == 0) { sleep(10); return 44; } else { wait(&status); //正常退出 if(WIFEXITED(status)){ printf("获取子进程返回值%d\n", WEXITSTATUS(status)); } } printf("猜猜我是啥\n"); }
output:
取子进程返回值44 猜猜我是啥
当你运行此段代码时候, 发现最少等待10s钟才能程序结束, 原因是wait是阻塞的, 父进程将等待子进程执行完毕, 获取其返回值。
#include <sys/wait.h> pid_t waitpid(pid_t pid, int * statloc, int options) 成功时返回终止的子进程ID(或0), 失败时返回 -1
具体参数:
参数 | 含义 |
---|---|
pid | 等待终止的子进程id, -1表示等待任意进程 |
statloc | 具体返回值指针 |
options | 具体参数常量 |
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid; int status; pid = fork(); //子进程 if (pid == 0) { return 44; } else { while (!waitpid(-1, &status, WNOHANG)) { sleep(3); printf("非阻塞等待\n"); } //正常退出 if (WIFEXITED(status)) { printf("获取子进程返回值%d\n", WEXITSTATUS(status)); } } printf("猜猜我是啥\n"); }
output:
非阻塞等待 获取子进程返回值44 猜猜我是啥
在这个示例里面, 我们使用了 waitpid 非阻塞等待子进程函数, 如果去掉我们的 while 等待, 一般是不会获取到子进程任何值就将结束了。
#include <stdio.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> void keycontrol(int sig) { if (sig == SIGINT) { puts("CTRL+C pressed."); } } void child(int sig) { int status; waitpid(-1, &status, WNOHANG); if (WIFEXITED(status)) { printf("%d\n", WEXITSTATUS(status)); } } int main() { int i; pid_t pid; signal(SIGINT, keycontrol); signal(SIGCHLD, child); //假装在运行 for (i = 0; i < 2; i++) { pid = fork(); if (pid == 0) { puts("我是子进程"); return 88; } else { puts("wait..."); sleep(10); } } return 0; }
output:
wait... 我是子进程 88 wait... 我是子进程 88
当你运行此代码时候发现, 我们的父进程并没有 sleep(10) 等待后返回, 而是早早的执行结束了。 发生信号时, 为了调用信号处理器, 将唤醒由于调用 sleep 函数而进入阻塞状态的进程, 所以 sleep 在信号发生时是失效的。
信号现在推荐使用 sigaction
echo_server.c
#include <stdio.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void read_childproc(int sig) { pid_t pid; int status; pid = waitpid(-1, &status, WNOHANG); printf("removed proc id: %d\n", pid); } int main() { //注册子进程信号 struct sigaction act; act.sa_sigaction = read_childproc; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, 0); int serv_sock = socket(PF_INET, SOCK_STREAM, 0); //初始化地址 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(9200); if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { printf("绑定地址失败 \n"); exit(1); } if (listen(serv_sock, 5) == 1) { printf("绑定端口失败 \n"); exit(1); } ////////接收请求/////////// struct sockaddr_in clnt_adr; int clnt_sock, adr_sz, str_len; pid_t pid; char buf[BUF_SIZE]; while (1) { adr_sz = sizeof(clnt_adr); clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz); if (clnt_sock == -1) { continue; } else { puts("new client connected..."); } pid = fork(); if (pid == -1) { puts("-1 -1 -1"); close(clnt_sock); continue; } //子进程处理 if (pid == 0) { //关闭复制到的父文件号 close(serv_sock); while ((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0) write(clnt_sock, buf, str_len); close(clnt_sock); puts("子进程受理"); //正常退出子进程 return 0; } else { puts("父进程不处理 clnt_sock"); close(clnt_sock); } } close(serv_sock); return 0; }
echo_client.c
#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #define BUF_SIZE 5 int main(int argc, char *argv[]) { char message[BUF_SIZE]; int str_len, recv_len, recv_cnt, i; struct sockaddr_in serv_addr, clnt_addr; int serv_sock = socket(PF_INET, SOCK_STREAM, 0); if (serv_sock == -1) { printf("socket() error"); exit(1); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); serv_addr.sin_port = htons(9200); if (connect(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { printf("connect() error"); exit(1); } while (1) { fputs("请输入您的信息,按Q键退出\n", stdout); fgets(message, 1024, stdin); //因为fgets会保留输入中换行符,故判断加\n if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) { break; } write(serv_sock, message, strlen(message)); str_len = read(serv_sock, message, BUF_SIZE); printf("Message from server: %s\n", message); } close(serv_sock); return 0; }
本文分享自微信公众号 - 呆呆熊的技术路(gh_93f28f51010a),作者:呆呆
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2019-05-15
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句