Programación del sistema Linux 46 Control de flujo de señales, realizado por depósito con fugas y depósito de tokens

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);
		
}

Supongo que te gusta

Origin blog.csdn.net/LinuxArmbiggod/article/details/114024853
Recomendado
Clasificación