什么叫阻塞,阻塞就是执行操作的时候,如果条件不满足则进程挂起,进入睡眠状态,知道等待的条件满足。阻塞的实现机制,应用程序是无法实现阻塞的,进程阻塞是通过Linux内核的等待队列来实现的。如果像将一个进程阻塞,就将它放入等待队列中,运行条件不满足的时候就将等待队列上的进程睡眠,实现阻塞的目的。实现函数:
0.wait_queue_head_t myQueue;
功能描述:创建一个等待队列头,相当于生成一个空节点
1.init_waitqueue_head(&myQueue);
功能描述:初始化队列头,相当于生成一个空节点
2.DECLARE_WAITQUEUE(name,current);
功能描述:定义一个等待队列任务,相当于生成一个链式队列的节点,但此时并没有放入等待队列中
参数说明:name是一个wait_queue_t类型的等待队列变量,第二个参数是进程,一般用current这个默认的
指针,代表的是用户当前进程。
3.add_wait_queue(myQueue,name);
功能描述:将等待队列任务放入等待队列中,相当于入队操作
参数说明:第一个参数是头结点,第二个参数是要插入的节点
4.remove_wait_queue(myQueue,name);
功能描述:将等待队列任务删除出队列,相当于出队操作
参数说明:第一个参数是头结点,第二个参数是要删除的节点
----------------------以下是等待队列的睡眠操作接口函数------------------------------
5.wait_event(myQueue, condition);
wait_event_interruptible(myQueue, condition);
功能描述:使等待队列上的进程睡眠,改睡眠不可/可被信号打断
参数说明:第一个参数是等待队列头变量,第二个参数是睡眠条件,如果是假则一直睡眠,为真就退出睡眠
6.wait_event_timeout(myQueue, condition, timeout);
wait_event_interruptible_timeout(myQueue, condition,timeout);
功能描述:使等待队列上的进程睡眠一段时间,改睡眠不可/可被信号打断
参数说明:第一个参数是等待队列头变量,第二个参数是睡眠条件,如果是假则睡眠一段时间,为真就退出
睡眠,timeout是睡眠时间
----------------------以下是等待队列的唤醒操作接口函数------------------------------
7.wake_up(myQueue);
wake_up_interruptible(myQueue);
功能描述:唤醒不可/可被信号打断的等待队列上的睡眠进程
代码实例
实例:将A.c代码中的read函数设置成阻塞模式,只有当B.c函数执行并向内核中写东西的时候才会读取内容,否则一直阻塞。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include "linux/cdev.h"
#include "linux/kdev_t.h"
#include "linux/fs.h"
#include "asm/uaccess.h"
#include "linux/sched.h"
MODULE_LICENSE ("GPL");
struct cdev myuart;
int major = 200;
int minor = 2;
int read_flag = 0;
wait_queue_head_t my_queue; 0.设置等待队列头结点
dev_t dev_id;
char kernel_buf[64] = {0};
struct file_operations var;
wait_queue_t node_var; 2.定义一个等待队列任务,相当于生成一个节点
int myopen(struct inode *pinode, struct file *pfile)
{
printk(KERN_INFO "myopen run\n");
return 0;
}
int myclose(struct inode *pinode, struct file *pfile)
{
printk(KERN_INFO "myclose run\n");
return 0;
}
ssize_t myread(struct file *pfile, char __user *buf, size_t len, loff_t *off)
{
int ret = 0;
DECLARE_WAITQUEUE(node_var,current); 2.定义一个等待队列任务,相当于生成一个节点
printk(KERN_INFO "myread run\n");
add_wait_queue(&my_queue, &node_var); 3.入队操作
wait_event(my_queue,read_flag != 0); 4.A.c程序执行read函数时,如果read_flag = 0,此
时阻塞,否则继续执行(初值为0,当write函数执行的时候会设置为1)
ret = copy_to_user(buf,kernel_buf,len);
read_flag = 0;
remove_wait_queue(&my_queue, &node_var); 6.remove函数放在这里,执行完以后就删除队列
return len-ret;
}
ssize_t mywrite(struct file *pfile, const char __user *buf, size_t len, loff_t *off)
{
int ret;
ret = copy_from_user(kernel_buf,buf,len) ;
printk(KERN_INFO "mywrite fun run") ;
read_flag = 1;
wake_up(&my_queue); 5.叫醒等待队列上的任务,此时可以继续进行读
return 30;
}
static int __init hello_init (void)
{
int ret = 0;
int ret1;
dev_id = MKDEV(major,minor) ;
ret = register_chrdev_region(dev_id,1, "uart");
if(ret == -1)
{
printk(KERN_INFO "dev_id = %d can't use \n",major);
ret1 = alloc_chrdev_region(&dev_id,minor,1, "uart");
if(ret1 == -1)
{
printk(KERN_INFO "dev_id error \n");
return -1;
}
else
{
printk(KERN_INFO "major = %d \n", MAJOR(dev_id));
}
}
else
{
printk(KERN_INFO "major = %d can use \n",major);
}
var.open = myopen;
var.release = myclose;
var.write = mywrite;
var.read = myread;
cdev_init(&myuart,&var);
cdev_add(&myuart,dev_id,1);
init_waitqueue_head(&my_queue); 1.初始化等待队列
return 0;
}
static void __exit hello_exit (void)
{
unregister_chrdev_region(dev_id, 1);
cdev_del(&myuart);
}
module_init (hello_init);
module_exit (hello_exit);
代码A.c
#include "stdio.h"
#include "fcntl.h"
#include "stdlib.h"
#include "unistd.h"
int main()
{
int fd;
int len;
char buf[64] = {0};
fd = open("./kkk.c",O_RDWR,0777);
if(fd == -1)
{
printf("open error\n");
return -1;
}
printf("read before\n");
len = read(fd,buf,64);
printf("read after: buf = %s,len = %d\n",buf,len);
close(fd);
return 0;
}
代码B.c
#include "stdio.h"
#include "fcntl.h"
#include "stdlib.h"
#include "unistd.h"
int main()
{
int fd;
int len;
char buf[64] = {0};
fd = open("./kkk.c",O_RDWR,0777);
if(fd == -1)
{
printf("open error\n");
return -1;
}
printf("please input send to kernel data\n");
scanf("%s",buf);
len = write(fd,buf,64);
while(1);
close(fd);
return 0;
}
转载请注明原文地址:https://ipadbbs.8miu.com/read-1563.html