管道

一、中断

硬件中断(外部中断):优先级较高 例如鼠标中断键盘中断

软件中断(内部中断):PU运行程序出错或者内部程序调用引起。


二、信号

信号是unix系统响应产生的事件,进程按照信号行动,信号因为某些错误产生,信号时在软件层次上对中断的一种模拟,通常称为软中断。

信号与中断的相似点:
(1)采用了相同的异步通信方式;
(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
(3)都在处理完毕后返回到原来的断点;
(4)对信号或中断都可进行屏蔽。
信号与中断的区别:
(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;
(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;

(3)中断响应是及时的,而信号响应通常都有较大的时间延迟


三、setitimer()函数

包含头文件<sys/time.h> 

函数原型

  1. int setitimer(int which, const struct itimerval *new_value, 
  2.             struct itimerval *old_value);  
其中which参数表示类型,可选的值有:
ITIMER_REAL:以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL:以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF:以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。

紧接着的new_value和old_value均为itimerval结构体,先看一下itimerval结构体定义:

struct itimerval {  
    struct timeval it_interval; /* next value */  
    struct timeval it_value;    /* current value */  
};  
  
struct timeval {  
    time_t      tv_sec;         /* seconds */  
    suseconds_t tv_usec;        /* microseconds */  
};  
settimer工作机制是,先对it_value倒计时,当it_value为零时触发信号,然后重置为it_interval,继续对it_value倒计时,一直这样循环下去。


三、匿名管道

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道,父子进程才能使用管道。

原型

int pipe(int fd[2]);

fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端

返回值:成功返回0,失败返回错误代码

#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>

int main(int argc, char *argv[])
{
	int pipefd[2];
	if (pipe(pipefd) == -1)
		//ERR_EXIT("pipe error");
	
	pid_t pid;
	pid = fork();
	if (pid == 0)
	{
		close(pipefd[0]);
		write(pipefd[1], "hello", 5);
		close(pipefd[1]);
		exit(EXIT_SUCCESS);
	}
	close(pipefd[1]);
	char buf[10] = {0}; 
	read(pipefd[0], buf, 10);
	printf("buf=%s\n", buf);
	return 0;
}

fcntl(pipefd[0],F_SETFL,O_NONBLOCK);  非阻塞,如果管道没有数据就直接返回-1;

所包含的头文件:

#include <sys/types.h>

#include <unistd.h>

 #include <fcntl.h>

当要写入的数据量不大于PIPE_BUF(linux/limits.h)时,linux将保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。



int main(void)
{
	char a[TEST_SIZE];
	char b[TEST_SIZE];

	memset(a, 'A', sizeof(a));
	memset(b, 'B', sizeof(b));

	int pipefd[2];

	int ret = pipe(pipefd);
	if (ret == -1)
		ERR_EXIT("pipe error");

	pid_t pid;
	pid = fork();
	if (pid == 0)
	{
		close(pipefd[0]);
		ret = write(pipefd[1], a, sizeof(a));
		printf("apid=%d write %d bytes to pipe\n", getpid(), ret);
		exit(0);
	}

	pid = fork();

	
	if (pid == 0)
	{
		close(pipefd[0]);
		ret = write(pipefd[1], b, sizeof(b));
		printf("bpid=%d write %d bytes to pipe\n", getpid(), ret);
		exit(0);
	}


	close(pipefd[1]);
	
	sleep(1);
	int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
	char buf[1024*4] = {0};
	int n = 1;
	while (1)
	{
		ret = read(pipefd[0], buf, sizeof(buf));
		if (ret == 0)
			break;
		printf("n=%02d pid=%d read %d bytes from pipe buf[4095]=%c\n", n++, getpid(), ret, buf[4095]);
		write(fd, buf, ret);

	}
	return 0;	
}

四、命名管道(FIFO)

只能在linux下创建,无法再window下创建。以一个pipe类型文件保存,无法编辑。

创建一个命名管道:$mkfifo  filename

命名管道也可以从程序里创建,相关函数有:

int mkfifo(const char *filename,mode_t mode);

read读端

int main(void)
{
	int ret = mkfifo("test",0666);
	printf("ret :%d\n",ret);
	
	int fd = open("test",O_RDONLY);
	printf("fd:%d\n",fd);
	char buf[256] = {0};
	while(1){
		ret = read(fd,buf,sizeof(buf));
		printf("buf:%s,ret:%d\n",buf,ret);
	}
	return 0;
}

write写端

int main(void)
{
	int ret = mkfifo("test",0666);
	printf("ret :%d\n",ret);
	 
	int fd =open("test",O_WRONLY);
	printf("fd:%d\n",fd);
	char buf[256]={0};
	while(1)
	{
		scanf("%s",buf);
		ret = write(fd,buf,strlen(buf));
	}

	return 0;
} 


全双工

作业:使用管道实现两个进程全双工通信,各自进行数据读写。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值