Experimento 1: Ejemplo de balde con fugas, control de flujo, salida cat10 caracteres por segundo a salida estándar
señal + alarma + pausa + señal interrumpe llamadas al sistema bloqueadas
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#define BUFSIZE 10
static volatile int loop = 0;
static void alrm_handler(int s)
{
alarm(1);//重新定时
loop = 1;
}
int main(int argc,char *argv[])
{
int sfd,dfd=1;
char buf[BUFSIZE];
int len,ret,pos;
if(argc < 2)
{
fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
exit(1);
}
signal(SIGALRM,alrm_handler);
alarm(1);
do
{
sfd = open(argv[1],O_RDONLY);
if(sfd < 0)
{
if(errno != EINTR)//防止是 信号打断阻塞的系统调用
{
perror("open()");
exit(1);
}
}
}while(sfd < 0);
while(1)
{
//休眠挂起 直到收到信号,重新开始执行while(!loop)循环,实现一秒一输出
// 这里也可以 不用pause(),while()后 执行空,但是这样 CPU 占用率会很高,一秒钟会在这里执行循环上亿次,所以用pause()替换,直接休眠等待信号来唤醒
/*
while(!loop)
;
*/
while(!loop)
pause();
loop = 0;
while((len = read(sfd,buf,BUFSIZE)) < 0)
{
if(errno == EINTR)//防止是 信号打断阻塞的系统调用
continue;
perror("read()");
break;
}
if(len == 0)
break;
//确保写进去 len 个字节
pos = 0;
while(len > 0)
{
ret = write(dfd,buf+pos,len);
if(ret < 0)
{
if(errno == EINTR) //防止是 信号打断阻塞的系统调用
continue;
perror("write()");
exit(1);
}
pos += ret;
len -= ret;
}
}
close(sfd);
}
Desventajas:
si está leyendo un dispositivo similar a una impresora y no hay datos en la impresora en ese momento, el programa siempre se repetirá en la posición de lectura
while((len = read(sfd,buf,BUFSIZE)) < 0)
{
if(errno == EINTR)//防止是 信号打断阻塞的系统调用
continue;
即 一直循环于:
读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。
读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。
读阻塞 ,打断阻塞 判断是假错误(信号打断阻塞的系统调用) 返回重新读 。。。。
Por lo tanto, el defecto del depósito con fugas es que si no hay datos, esperará en un bucle hasta que haya datos. Si la cantidad de datos es repentinamente grande, los datos no se pueden leer rápidamente, solo 10 bytes por segundo lentamente. Leer n veces
La ventaja del depósito de tokens es que cuando no hay datos para leer, acumulará sus propios permisos, lo que significa que si no ha habido datos durante 30 segundos antes de leer durante 30 segundos, entonces se guardarán 30 permisos y esperará hasta hay datos. Utilice los primeros 30 permisos rápidamente y lea 30 veces en rápida sucesión.
Experimento 2: Ejemplo de depósito de tokens
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#define CPS 10
#define BUFSIZE CPS
#define BURST 100
static volatile int token = 0;
static void alrm_handler(int s)
{
alarm(1);
token++;
if(token > BURST)
token = BURST;
}
int main(int argc,char *argv[])
{
int sfd,dfd=1;
char buf[BUFSIZE];
int len,ret,pos;
if(argc < 2)
{
fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
exit(1);
}
signal(SIGALRM,alrm_handler);
alarm(1);
do
{
sfd = open(argv[1],O_RDONLY);
if(sfd < 0)
{
if(errno != EINTR)//signal
{
perror("open()");
exit(1);
}
}
}while(sfd < 0);
while(1)
{
while(token <= 0)
pause();
token--;
while((len = read(sfd,buf,BUFSIZE)) < 0)
{ if(errno == EINTR)//signal
continue;
perror("read()");
break;
}
if(len == 0)
break;
//确保写进去 len 个字节
pos = 0;
while(len > 0)
{
ret = write(dfd,buf+pos,len);
if(ret < 0)
{
if(errno == EINTR) //signal
continue;
perror("write()");
exit(1);
}
pos += ret;
len -= ret;
}
}
close(sfd);
}