进程相关概念
程序和进程
程序:死的。只占用磁盘空间。
进程;活的。运行起来的程序。占用内存、cpu 等系统资源。
并发和并行
并发和并行:并行是宏观上并发,微观上串行
并发:是同一个cpu,执行不同的进程,使用不同的 时间片,只是有一个进程在执行
并行:是不同的cpu,使得多个进程同时的执行
进程控制块
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
//........
struct pipe_inode_info *splice_pipe;
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
#ifdef CONFIG_FAULT_INJECTION
int make_it_fail;
#endif
};
// /usr/src/linux-headers-3.16.0-30/include/linux/sched.h文件中可以查看struct task_struct 结构体定义。其内部成员有很多
/*
* 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非负整数。
* 进程的状态,有就绪、运行、挂起、停止等状态。
* 进程切换时需要保存和恢复的一些CPU寄存器。
* 描述虚拟地址空间的信息。
* 描述控制终端的信息。
* 当前工作目录(Current Working Directory)。
* umask掩码。
* 文件描述符表,包含很多指向file结构体的指针。
* 和信号相关的信息。
* 用户id和组id。
* 会话(Session)和进程组。
* 进程可以使用的资源上限(Resource Limit)。
*/
- 进程状态
进程基本的状态有5种。分别为初始态,就绪态,运行态 , 挂起态与终止态。
其中初始态为进程准备阶段,常与就绪态结合来看。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iRlWn3RV-1671507698300)(file:///C:\Users\dongfang\AppData\Local\Temp\ksohtml9364\wps2.jpg)]
环境变量
常见的环境变量
1、PATH:用来记录文件的可执行路径,
echo $PATH
2、SHELL:用来记录当前Shell,它的值通常是/bin/bash。
echo $SHELL
3、TERM:当前终端类型,在图形界面终端下它的值通常是xterm,
echo $TERM
4、LANG:语言和locale,决定了字符编码以及时间、货币等信息的显示格式。
5、HOME:当前用户主目录的路径,很多程序需要在主目录下保存配置文件,使得每个用户在运行该程序时都有自己的一套配置。
常用函数
1、getenv函数:获取环境变量值
char *getenv(const char *name);
成功:返回环境变量的值;失败:NULL (name不存在)
2、setenv函数:设置环境变量的值
int setenv(const char *name, const char *value, int overwrite);
成功:0;失败:-1
参数overwrite:若存在是否覆盖
1:覆盖原环境变量
若存在且overwrite == 0 则忽略value
0:不覆盖。(该参数常用于设置新环境变量,如:ABC = haha-day-night)
3、unsetenv函数:删除环境变量name的定义
int unsetenv(const char *name);
成功:0;失败:-1
注意事项:name不存在仍返回0(成功),当name命名为"ABC="时则会出错。
查看当前进程所有环境变量
#include <stdio.h>
extern char **environ;//eg : environ[1] = "SHLVL=1"
int main(void){
int i;
for(i = 0; environ[i] != NULL; i++){
printf("%s\n", environ[i]);
}
return 0;
}
获取name对应环境变量
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ;
char *my_getenv(const char *name){
char *p = NULL;
int i, len;
for(i = 0; environ[i] != NULL; i++){
p = strstr(environ[i], "=");//获取“=”所在位置
len = p - environ[i];//获取环境变量name的长度
if(strncmp(name, environ[i], len) == 0){//对比是否相等
return p+1;//返回对应的环境变量
}
}
return NULL;
}
int main(int argc, char *argv[]){
char *p = NULL;
p = getenv(argv[1]);
//p = my_getenv(argv[1]);
if (p == NULL)
printf("there is no match\n");
else
printf("%s\n", p);
return 0;
}
/*执行结果
ubuntu@ubuntu:~/LearnCPP/linux_test/path_test$ ./getenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
*/
setenv和unsetenv例子
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *val;
const char *name = "ABD";
val = getenv(name);
printf("1, %s = %s\n", name, val);
setenv(name, "haha-day-and-night", 1);//设置覆盖环境变量值为haha-day-and-night
val = getenv(name);
printf("2, %s = %s\n", name, val);
#if 0
unsetenv("ABD");//删除环境变量ABD
val = getenv(name);
printf("3, %s = %s\n", name, val);
#else
int ret = unsetenv("ABD="); //name=value:value
printf("ret = %d\n", ret);
val = getenv(name);
printf("3, %s = %s\n", name, val);
#endif
return 0;
}
/*执行结果
ubuntu@ubuntu:~/LearnCPP/linux_test/path_test$ ./setenv
1, ABD = 123
2, ABD = haha-day-and-night
ret = -1
3, ABD = haha-day-and-night
正确删除环境变量
ubuntu@ubuntu:~/LearnCPP/linux_test/path_test$ ./setenv
1, ABD = 123
2, ABD = haha-day-and-night
3, ABD = (null)
*/
进程控制
fork()
、getpid()
、getppid()
pid_t fork(void);
失败返回-1;成功返回① 父进程返回子进程的ID(非负) ②子进程返回 0 。
创建一个子线程。pid_t类型表示进程ID,但为了表示-1,它是有符号整型。
(0不是有效进程ID,init最小,为1)。不是fork函数能返回两个值,而是fork后,fork函数变为两
个进程,每个进程各自返回一个。
pid_t getpid(void);
获取当前进程id
pid_t getppid(void);
获取当前进程的父进程id
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
int main(int argc,char* argv[]){
printf("before fork1\n");
printf("before fork2\n");
printf("before fork3\n");
printf("before fork4\n");
pid_t pid = fork();
if(pid == -1){
perror("fork err");
exit(1);
}else if(pid == 0){
printf("children pid is create -- pid = %d \n,parent pid = %d",getpid(),getppid());
}else if(pid >0){
printf("parent pid = %d create children pid is %d\n,parent parent pid = %d \n",getpid(),pid,getppid());
}
printf("-----------end of file\n");
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/pcb_test$ ./pcb_test
before fork1
before fork2
before fork3
before fork4
parent pid = 7083 create children pid is 7084
,parent parent pid = 7077
-----------end of file
children pid is create -- pid = 7084
,parent pid = 7083-----------end of file
*/
循环创建多个子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
int main(int argc,char* argv[]){
int i =0;
pid_t pid;
for(i =0;i<5;i++){
pid = fork();
if(pid == 0){
break;
}
}
if(i == 5){
sleep(5);
printf("parent process\n");
}else{
sleep(i);//让进程按照顺序打印
printf("I am %dth chilren\n",i+1);
}
printf("-----------end of file\n");
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/pcb_test$ ./fork_loop
I am 1th chilren
-----------end of file
I am 2th chilren
-----------end of file
I am 3th chilren
-----------end of file
I am 4th chilren
-----------end of file
I am 5th chilren
-----------end of file
parent process
-----------end of file
*/
getuid()
、getgid()
、geteuid()
、getegid()
获取当前进程实际用户ID
uid_t getuid(void);
获取当前进程有效用户ID
uid_t geteuid(void);
获取当前进程使用用户组ID
gid_t getgid(void);
获取当前进程有效用户组ID
gid_t getegid(void);
进程共享
父子进程相同:
刚
fork
后。data
段、text
段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式
父子进程不同:
进程 id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集
父子进程共享:
读时共享、写时复制。———————— 全局变量。
共享内容:1、文件描述符 2.
mmap
映射区。
父子进程GDB调试
gdb
调试:
设置父进程调试路径:
set follow-fork-mode parent
(默认)设置子进程调试路径:
set follow-fork-mode child
注意,一定要在
fork
函数调用之前设置才有效。
exec函数族
当进程调用一种
exec
函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。将当前进程的.text
、.data
替换为所要加载的程序的.text
、.data
,然后让进程从新的.text
第一条指令开始执行,但进程ID不变。
exec函数族函数
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 execve(const char *path, char *const argv[], char *const envp[]);
exec函数一般规律
exec
函数族一般规律:
exec
函数一旦调用成功,即执行新的程序,不返回。只有失败才返回,错误值-1,所以通常我们
直接在exec
函数调用后直接调用perror()
,和exit()
,无需 if 判断。
- l(
list
) :命令行参数列表- p(
path
) :搜索 file 时使用 path 变量- v(
vector
) :使用命令行参数数组- e(
environment
) :使用环境变量数组,不适用进程原有的环境变量,设置新加载程序运行的环境变量事实上,只有
execve
是真正的系统调用,其他 5 个函数最终都调用execve
,是库函数,所以execve
在man
手册第二节,其它函数在man
手册第 3 节。
execl
执行test
程序
- test程序
#include <stdio.h>
int main(){
printf("hello my name is child process\n");
return 0;
}
- execl程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
int main(int argc,char* argv[]){
pid_t pid = fork();
if(pid == -1){
perror("fork error");
exit(1);
}else if(pid == 0){
execl("./test","./test",NULL);//NULL哨兵
perror("exec error");
exit(1);
}else if(pid >0){
sleep(1);
printf("i am parent : %d \n",getpid());
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/exec_test$ ./exec_test2
hello my name is child process
i am parent : 9095
*/
execl
执行ls
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
int main(int argc,char* argv[]){
pid_t pid = fork();
if(pid == -1){
perror("fork error");
exit(1);
}else if(pid == 0){
execl("/bin/ls","ls","-l",NULL);//NULL哨兵
perror("exec error");
exit(1);
}else if(pid >0){
sleep(1);
printf("i am parent : %d \n",getpid());
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/exec_test$ ./exec_test4
总用量 132
-rwxrwxr-x 1 ubuntu ubuntu 8912 9月 7 16:25 exec_ps
-rw-rw-r-- 1 ubuntu ubuntu 403 9月 7 16:25 exec_ps.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:18 exec_test
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:24 exec_test2
-rw-rw-r-- 1 ubuntu ubuntu 402 9月 7 15:54 exec_test2.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:28 exec_test3
-rw-rw-r-- 1 ubuntu ubuntu 399 9月 7 15:28 exec_test3.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:56 exec_test4
-rw-rw-r-- 1 ubuntu ubuntu 404 9月 7 15:56 exec_test4.c
-rw-rw-r-- 1 ubuntu ubuntu 400 9月 7 15:18 exec_test.c
-rw-rw-r-- 1 ubuntu ubuntu 34074 9月 7 16:25 ps.out
-rwxrwxr-x 1 ubuntu ubuntu 8600 9月 7 15:24 test
-rw-rw-r-- 1 ubuntu ubuntu 91 9月 7 15:22 test.c
i am parent : 9208
*/
execlp
函数执行ls
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
int main(int argc,char* argv[]){
pid_t pid = fork();
if(pid == -1){
perror("fork error");
exit(1);
}else if(pid == 0){
execlp("ls","ls","-l",NULL);//NULL哨兵
perror("exec error");
exit(1);
}else if(pid >0){
sleep(1);
printf("i am parent : %d \n",getpid());
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/exec_test$ ./exec_test
总用量 132
-rwxrwxr-x 1 ubuntu ubuntu 8912 9月 7 16:25 exec_ps
-rw-rw-r-- 1 ubuntu ubuntu 403 9月 7 16:25 exec_ps.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:18 exec_test
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:24 exec_test2
-rw-rw-r-- 1 ubuntu ubuntu 402 9月 7 15:54 exec_test2.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:28 exec_test3
-rw-rw-r-- 1 ubuntu ubuntu 399 9月 7 15:28 exec_test3.c
-rwxrwxr-x 1 ubuntu ubuntu 8920 9月 7 15:56 exec_test4
-rw-rw-r-- 1 ubuntu ubuntu 404 9月 7 15:56 exec_test4.c
-rw-rw-r-- 1 ubuntu ubuntu 400 9月 7 15:18 exec_test.c
-rw-rw-r-- 1 ubuntu ubuntu 34074 9月 7 16:25 ps.out
-rwxrwxr-x 1 ubuntu ubuntu 8600 9月 7 15:24 test
-rw-rw-r-- 1 ubuntu ubuntu 91 9月 7 15:22 test.c
i am parent : 9235
*/
execlp
执行ps aux
命令,并存入文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main(int argc,char* argv[]){
int fd = open("ps.out",O_RDWR|O_CREAT|O_TRUNC,0664);
if(fd == -1){
perror("open error");
exit(1);
}
dup2(fd,STDOUT_FILENO);
pid_t pid = fork();
if(pid == 0){
execlp("ps","ps","-aux",NULL);
close(fd);
perror("exec error");
exit(1);
}
return 0;
}
执行后的结果
孤儿进程和僵尸进程
孤儿进程:
父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。
僵尸进程:
子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其
无效。这里要注意,每个进程结束后都必然会经历僵尸态,时间长短的差别而已。
子进程终止时,子进程残留资源 PCB 存放于内核中,PCB 记录了进程结束原因,进程回收就是回
收 PCB。回收僵尸进程,得 kill 它的父进程,让孤儿院去回收它。
回收子进程
wait()
函数
回收子进程退出资源, 阻塞回收任意一个。
pid_t wait(int *status)
参数:(传出) 回收进程的状态。
返回值:成功: 回收进程的 pid
失败: -1,errno
wait阻塞回收单个子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char* argv[]){
pid_t pid , wpid;
int status;
pid = fork();
if(pid == 0){
printf("child my parent pid = %d,going to sleep 5s\n",getppid());
sleep(5);
printf("------child die------\n");
}else if(pid >0){
wpid = wait(&status);
if(wpid == -1){
perror("wait error");
exit(1);
}
printf("I am parent ,pid = %d,myson = %d\n",getpid(),pid);
printf("parent finish\n");
}else{
perror("fork");
return 1;
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/wait_test$ ./wait_test
child my parent pid = 9511,going to sleep 5s
------child die------
I am parent ,pid = 9511,myson = 9512
parent finish
*/
wait获取子进程退出值和异常终止信号
获取子进程正常终止值:
WIFEXITED(status)
--》 为真 --》调用WEXITSTATUS(status)
–》 得到 子进程 退出值。获取导致子进程异常终止信号:
WIFSIGNALED(status)
--》 为真 --》调用WTERMSIG(status)
--》 得到 导致子进程异常终止的信号编号。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char* argv[]){
pid_t pid, wpid;
int status;
pid = fork();
//一次wait和waitpid一次只能回收一个子进程
//wait来说是随机的,那个先,就先回收那个子进程
if(pid == 0 ){//子进程
printf("this is child process: child id = %d,sleep 10s\n",getpid());
sleep(10);
printf("-------child die--------\n");
return 87;
}else if(pid > 0){//父进程
wpid = wait(&status);
if(wpid == -1){
perror("wait error");
exit(1);
}else{
if(WIFEXITED(status)){//正常结束
printf("child process exit : %d\n",WEXITSTATUS(status));
}else if(WIFSIGNALED(status)){//被信号kill
printf("child process kill by singal:%d",WTERMSIG(status));
}else if(WIFSTOPPED(status)){//被信号stop
printf("child process stop by singal:%d",WSTOPSIG(status));
}
}
}else{
perror("fork error");
return -1;
}
return 0;
}
/*
//正常终止
ubuntu@ubuntu:~/LearnCPP/linux_test/wait_test$ ./wait_test3
this is child process: child id = 9589,sleep 10s
-------child die--------
child process exit : 87
*/
waitpid()
函数
pid_t waitpid(pid_t pid, int *status, int options)
waitpid(-1, &status, 0)相当于wait(&status);
参数:
pid
:指定回收某一个子进程pid
> 0: 待回收的子进程
pid
-1:任意子进程
0:同组的子进程。
status
:(传出) 回收进程的状态。
options
:WNOHANG
指定回收方式为,非阻塞。如果是0表示阻塞返回值:
> 0 : 表成功回收的子进程
pid
0 : 函数调用时, 参 3 指定了WNOHANG
, 并且,没有子进程结束。
-1: 失败。errno
回收多个子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
int n = 5, i;
pid_t pid, wpid;
for (i = 0; i < 5; i++){
pid = fork();
if (pid == 0)
{
break;
}
}
if (n == i){ //父进程
// sleep(n);
// printf("I am parent , pid = %d",getpid());
// while ((wpid = waitpid(-1, NULL, 0))) { //阻塞的回收
// printf("wait child %d\n", wpid);
// if (wpid == -1){
// break;
// }
// }
while((wpid = waitpid(-1,NULL,WNOHANG) != -1)){//非阻塞的回收
sleep(1);
if(wpid > 0){
printf("wait child %d\n",wpid);
}else if (wpid == 0){
sleep(1);
printf("wait child finish");
continue;
}
}
}
else{
sleep(i);
printf("I am %dth child ,pid = %d\n", i + 1, getpid());
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/waitpid_test$ ./waitpid_test
I am 1th child ,pid = 9749
wait child 1
I am 2th child ,pid = 9750
I am 3th child ,pid = 9751
wait child 1
I am 4th child ,pid = 9752
wait child 1
I am 5th child ,pid = 9753
wait child 1
wait child 1
wait child 1
*/
回收单个进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char* argv[]){
pid_t pid, wpid;
int i = 0;
for (i = 0; i < 5;i++){//循环产生5个子进程
pid = fork();//父进程执行
if(pid == 0){//子进程不在衍生,子进程执行
break;
}
if(i == 2){//第三个子进程
wpid = pid;//父进程执行
}
}
if( 5 == i){//父进程
sleep(1);
pid_t p = waitpid(wpid, NULL, 0);//阻塞回收wpid进程
if(p > 0){
printf("wait pid = %d finish\n",wpid);
}
}
else { //子进程
//
sleep(i);
printf("I am %dth child , my pid = %d\n",i+1,getpid());
}
return 0;
}
进程间通信
常见的进程间通信
进程间通信的常用方式:
管道:简单
信号:开销小
mmap
映射:非血缘关系进程间
socket
(本地套接字):稳定
管道pipe
调用
pipe系统函数
即可创建一个管道。有如下特质:
- 其本质是一个伪文件(实为内核缓冲区)
- 由两个文件描述符引用,一个表示读端,一个表示写端。
- 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(
4k
)实现。
管道的局限性: ① 数据不能进程自己写,自己读。
② 管道中数据不可反复读取。一旦读走,管道中不再存在。
③ 采用半双工通信方式,数据只能在单方向上流动。
④ 只能在有公共祖先的进程间使用管道。
int pipe(int pipefd[2]);
成功:0;失败:-1,设置errno
函数调用成功返回r/w
两个文件描述符。无需open
,但需手动close
。规定:fd[0] → r
;fd[1] → w
。用于有血缘关系进程之间的通信
pipe
通信demo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
//管道命令pipe test
int main(int argc,char* argv[]){
int fd[2];//管道
int ret;
pid_t pid;
char *buf = "hello world\n";
char readBuf[1024];//接收管道数据buf
ret = pipe(fd);//创建管道并打开
if(ret == -1){
perror("pipe error");
exit(1);
}
pid = fork();
if (pid > 0){//父进程
close(fd[0]);//关闭读段
write(fd[1],buf,strlen(buf));//向写管道中写入
sleep(1);//保证子进程先于父进程结束
close(fd[1]); //关闭写管道
}else if(pid == 0){//子进程
close(fd[1]);//关闭写管道
ret = read(fd[0],readBuf,sizeof(readBuf));
printf("child read %d char\n",ret);
write(STDOUT_FILENO, readBuf, ret);
close(fd[0]);
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/pipe_test$ ./pipe_test
child read 12 char
hello world
*/
pipe
实现ls | wc -l
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
//利用pipe管道通信实现ls | wc -l
//使用dup2 fork pipe等函数
int main(int argc,char* argv[]){
int fd[2];
int ret;
pid_t pid;
ret = pipe(fd);
if(ret == -1){
perror("pipe error");
exit(1);
}
pid = fork();
if(pid == -1){
perror("fork error");
exit(1);
}else if(pid == 0){//子程序进行写端,将STDOUT重定向到fd[1]中
close(fd[0]);//关闭读端
dup2(fd[1],STDOUT_FILENO);//重定向
execlp("ls","ls",NULL);//执行ls命令
close(fd[1]);
perror("execlp error");
exit(1);
}
else if (pid > 0)
{ //父程序进行读端,将STDIN重定向到fd[1]中
close(fd[1]);
dup2(fd[0],STDIN_FILENO);//重定向
execlp("wc","wc","-l",NULL);
close(fd[0]);
perror("execlp error");
exit(1);
}
return 0;
}
/*
ubuntu@ubuntu:~/LearnCPP/linux_test/pipe_test$ ./pipe1
10
*/
fifo
命名管道
int mkfifo(const char *pathname, mode_t mode);
成功:0; 失败:-1** 可以应用于无血缘关系进程之间的通信
创建fifo
命名管道
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
void sys_errno(char* str){
perror("str");
exit(1);
}
int main(int argc,char** argv){
int ret = mkfifo("myfifo",0664);
if(ret == -1){
sys_errno("fifo err");
}
return 0;
}
程序1写fifo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc,char* argv[]){
int fd,i;
char buf[4096];
fd = open(argv[1],O_WRONLY);
if(fd<0){
perror("open err");
exit(1);
}
i = 0;
while(1){
sprintf(buf, "hello itcast %d\n",i++);
write(fd,buf,strlen(buf));
sleep(1);
}
close(fd);
return 0;
}
程序2读取fifo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
void sys_errno(char* str){
perror("str");
exit(1);
}
int main(int argc,char* argv[]){
int fd,i,len;
char buf[4096];
fd = open(argv[1],O_RDONLY);
if(fd<0){
perror("open err");
exit(1);
}
i = 0;
// write(fd,"nihao\n",strlen("nihao\n"));
while(1){
len = read(fd,buf,strlen(buf));
write(STDOUT_FILENO,buf,len);
sleep(1);
}
close(fd);
return 0;
}
fifo
执行结果
s