学习笔记
APUE这本书内容
读管道
1.管道中有数据,read返回实际读到的字节数
2.管道没有数据:
1)判断管道的写端是否被全部关闭,全部关闭,read返回为0
2)管道的写端没有全部被关闭,read阻塞等待。(不久的将来,可能有数据传达,此时会让出cpu)
写管道
1.管道读端全部被关闭,进程异常终止(也可以使用捕捉SIGPIPE信号,使进程不终止)
2.管道读端没有全部被关闭:
1)管道已满,write阻塞
2)管道未满,write将数据写入,并返回实际写入的字节数。
程序: 父进程一上来就跑去睡觉,子进程读不到数据,
根据读写行为可知道子进程处于read阻塞等待。
$cat mypipe.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int ret;
int fd[2];
pid_t pid;
char *str ="hello pipe\n";
char buf[1024];
ret = pipe(fd);
if(-1 == ret)
{
sys_err("pipe error!");
}
pid = fork();
if(pid > 0)
{
close(fd[0]); //guanbi du duan
sleep(3);
write(fd[1],str,strlen(str));
close(fd[1]);
}
else if(0 == pid)
{
close(fd[1]);//guanbi xie duan
ret = read(fd[0],buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
close(fd[0]);
}
return 0;
}
$make mypipe
gcc mypipe.c -o mypipe -Wall -g
$./mypipe
$hello pipe
提示: $./mypipe 三秒之后才显示 $hello pipe
如果管道写端全部被关闭,根据管道读写行为,
这个时候read 返回值为0.
修改程序如下:
$cat mypipe.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int ret;
int fd[2];
pid_t pid;
char *str ="hello pipe\n";
char buf[1024];
ret = pipe(fd);
if(-1 == ret)
{
sys_err("pipe error!");
}
pid = fork();
if(pid > 0)
{
close(fd[0]); //guanbi du duan
sleep(3);
// write(fd[1],str,strlen(str));//不去写,直接关闭写端
close(fd[1]);
}
else if(0 == pid)
{
close(fd[1]);//guanbi xie duan
ret = read(fd[0],buf,sizeof(buf));
printf("child read ret = %d\n",ret);
write(STDOUT_FILENO,buf,ret);
close(fd[0]);
}
return 0;
}
$make mypipe
gcc mypipe.c -o mypipe -Wall -g
mypipe.c: In function ‘main’:
mypipe.c:18:11: warning: unused variable ‘str’ [-Wunused-variable]
18 | char *str ="hello pipe\n";
| ^~~
$./mypipe
$child read ret = 0
可以看到read为0,相当于文件末尾一样。
管道已满的没有办法测试,向4096的缓冲区,不断写入数据,还要保证读那一端要比较慢。
实际上,管道是有缓冲区构造的,当内核发现缓冲区满了(4096),它会自动给它扩容。
内核2.7还是2.6版本之后,有这个功能。