阻塞与非阻塞

阻塞与非阻塞

所谓阻塞,就是等待某件事情发生。比如调用read读取按键时,如果没有按键数据则 read 函数不会返回,它会让线程休眠等待。

使用 poll 时,如果传入的超时时间不为 0,这种访问方法也是阻塞的。
使用 poll 时,可以设置超时时间为 0,这样即使没有数据它也会立刻返回,这就是非阻塞方式。能不能让 read 函数既能工作于阻塞方式,也可以工作于非阻塞方式? 可以!

APP 调用open函数时,传入O_NONBLOCK,就表示要使用非阻塞方式;默认是阻塞方式。

注意:对于普通文件、块设备文件, O_NONBLOCK不起作用。
注意:对于字符设备文件,O_NONBLOCK起作用的前提是驱动程序针对O_NONBLOCK做了处理。

只能在 open 时表明 O_NONBLOCK 吗?在 open 之后,也可以通过 fcntl 修改为阻塞或非阻塞。

应用编程

open 时设置:

int fd = open(/dev/xxx”, O_RDWR | O_NONBLOCK);     /* 非阻塞方式 */
int fd = open(/dev/xxx”, O_RDWR );                 /* 阻塞方式 */

open 之后设置

int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);      /* 非阻塞方式 */
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);     /* 阻塞方式 */

先非阻塞读10次,再以阻塞的方式读数据


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>

static int fd;

/*
 * ./button_test /dev/100ask_button0
 *
 */
int main(int argc, char **argv)
{
	int val;
	struct pollfd fds[1];
	int timeout_ms = 5000;
	int ret;
	int	flags;

	int i;
	
	/* 1. 判断参数 */
	if (argc != 2) 
	{
		printf("Usage: %s <dev>\n", argv[0]);
		return -1;
	}


	/* 2. 打开文件 */
	fd = open(argv[1], O_RDWR | O_NONBLOCK);
	if (fd == -1)
	{
		printf("can not open file %s\n", argv[1]);
		return -1;
	}

	for (i = 0; i < 10; i++) 
	{
		if (read(fd, &val, 4) == 4)
			printf("get button: 0x%x\n", val);
		else
			printf("get button: -1\n");
	}

	flags = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);

	while (1)
	{
		if (read(fd, &val, 4) == 4)
			printf("get button: 0x%x\n", val);
		else
			printf("while get button: -1\n");
	}
	
	close(fd);
	
	return 0;
}

驱动编程

static ssize_t drv_read(struct file *fp, char __user *buf, size_t count, loff_t *ppo
s)
{
    if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
        return -EAGAIN;
    wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
    ……
}

从驱动代码也可以看出来,当 APP 打开某个驱动时,在内核中会有一个struct file 结构体对应这个驱动,这个结构体中有 f_flags,就是打开文件时的标记位;可以设置 f_flasgs 的 O_NONBLOCK位,表示非阻塞;也可以清除这个位表示阻塞。

驱动程序要根据这个标记位决定事件未就绪时是休眠和还是立刻返回。

编译

在这里插入图片描述

测试

把编译出来的设备树文件拷贝到/boot目录下
在这里插入图片描述
reboot重启
安装驱动,强制安装

insmod gpio_key_drv.ko

在这里插入图片描述
执行测试程序

./button_test /dev/100ask_button0

在这里插入图片描述
先输出-1,因为没有中断(此时是非阻塞),10次之后是阻塞的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值