Unbuffered low-level IO and Buffered high-level IO

 
Unbuffered low-level IO and Buffered high-level IO
1,概述
Unix提供的函数如read,write等都属于Unbuffered IO函数。
Standard IO提供的函数如fread,fwrite都属于Buffered IO函数。Standard IO的底层都是调用read,write来实现的。
2,Unbuffered
Unbuffered意味着每次调用read,write都引起内核的一个系统调用,将对文件进行实际的读写。
3,Buffered
Buffer为了最少次数的调用read,write函数,从而提升性能。
Stream
Buffering type
Stderr
Always unbufferer
Streams referring to a
Terminal (interactive) device
Line Bufferer
All other streams
Full Buffer
4,例子
[1] 父进程发送消息给子进程,子进程读取消息后返回,父进程等待子进程结束
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
 
int main() {
pid_t pid ;
int fd[2] ;
int rtn ;
 
pipe( fd ) ;
pid = fork() ;
if ( pid == 0 ) { // child
              close ( fd[1] ) ;
              char info[56]= { 0 } ;
              dup2( fd[0] , STDIN_FILENO ) ;
              //read( fd[0] , info , 56 ) ;
              read( STDIN_FILENO , info , 56 ) ; ß 读取父进程发送的信息
              printf("child from parent: %s/n" , info);
              close ( fd[0] ) ;
             
              return 0 ;
} else { // parent
              char * pstr = "parent send to child : " ;
             
close( fd[0] ) ;
              dup2( fd[1] , STDOUT_FILENO ) ;
              printf("%s" ,pstr );  ß 如果没有 fflush 调用的话, child 将在 read 处阻塞
              fflush( stdout ) ;    ß 因为是 fully buffered
              /* 管道中一个进程的输出,作为下一个进程的输入,大概就是使用这种方式 */
              //write( fd[1] , pstr , strlen("parent: send to child/n") ) ;
              //write( STDOUT_FILENO , pstr , strlen("parent: send to child/n") ) ;
              // 如果使用以上任意一种的话,将没有阻塞现象,因为是 unbuffered
 
              waitpid( pid , &rtn , 0) ; ß 等待 child 结束
              close ( fd[1] ) ;
}
 
return 0 ;
}
 
[2]
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
 
int      glob = 6 ;      
char     buf[] = "a write to stdout/n";
 
int main(void) {
    pid_t     pid;
    int       var = 88 ;
    // write unbuffered
    write(STDOUT_FILENO, buf, sizeof(buf)-1) ;
    printf("before fork/n");    ß line buffered ,如果和 interactive terminal 连接的话
                             ß 否则就是 fully buffered
 
    if ((pid = fork()) < 0) {
        printf("fork error");
        return (-1) ;
    } else if (pid == 0) { // child
        glob++;
        var++;
    } else { // parent
        sleep(2);
    }
 
    printf("pid = %d, glob = %d, var = %d/n", getpid(), glob, var);
    return (0);
}
程序的运行结果为:
$ ./a.out
a write to stdout
before fork
pid = 430, glob = 7, var = 89
pid = 429, glob = 6, var = 88
$ ./a.out > temp.out
$ cat temp.out
a write to stdout
before fork
pid = 432, glob = 7, var = 89
before fork
pid = 431, glob = 6, var = 88
解释一下:
[1] write是unbuffered,所以在执行fork时,已经输出到stdout中了。
[2] 直接执行时,stdout和interactive terminal相连接,所以是line buffered。Printf执行后,就被输出到stdout中了。因为字符串以换行符结束。
[3] 输出重定向执行时, stdout 被重定向为文件 temp.out 。所以是 fully buffered Printf 执行后,并没有输出到 stdout 中。后面执行了 fork ,输出缓冲区也被拷贝到了 child 中。在 parent child 中,再执行 printf 时,实际是向输出缓冲区追加内容。当 parent child 结束时,输出缓冲区的内容被 flush
 
由于这些问题很subtle,所以我们要特别注意这方面的问题。
 

你可能感兴趣的:(IO,Stream,unix,buffer,Terminal)