IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 进程的休眠与唤醒(等待队列) -> 正文阅读

[系统运维]进程的休眠与唤醒(等待队列)

1、进程休眠

(1)进程有三种基本状态:就绪态、阻塞态、运行态。
<1>阻塞态:进程缺少除了CPU之外的某些资源,因此该进程不能被运行,被阻塞住了不能被CPU调度;
<2>就绪态:进程分配到了除CPU之外的所有资源,等待CPU调度执行;
<3>运行态:进程获得CPU资源,程序在CPU上运行;
(2)进程休眠:进程休眠就是进程因为缺少除了CPU之外的某些资源而进入阻塞态,会从调度器的运行队列中移走该进程,并把进程放到等待资源的队列中,直到分配到资源从而被唤醒,再次进入到就绪态,等待CPU调度;

2、进程休眠的注意事项

进程进入休眠是很容易的,只要申请不到资源都可能休眠,但是我们要保证进程以一种安全的方式进入休眠,也就是进程进入休眠后,
将来能被成功的唤醒;
(1)永远不要在原子上下文中进入休眠,原子操作本身就是要不可中断的一次性执行完;
(2)不能在拥有锁的时候进入休眠,否则可能会造成死锁;比如A进程在拥有自旋锁时进入休眠等待B进程唤醒,B进程需要先获得自旋锁进行一些操作才能唤醒A进程,
B进程等待A进程释放自旋锁,A进程等待B进程唤醒后才能释放锁,这就死锁了;
(3)拥有信号量时进程是可以进入休眠的,但是要非常注意:用于信号量而休眠的代码必须很短,并且还要确保拥有信号量斌不会阻塞最终唤醒我们自己的那个进程;
(4)进程被唤醒时,无法知道休眠了多长时间或者休眠期间都发生了什么事,所以在进程被唤醒后不要对状态进行任何假定,必须去检查我们等待的条件是否为真,因为
同时可能有别的进程因为等待同一资源而休眠,我们等待的资源可能被别的进程拿走;
(5)除非知道有其他进程会在其他地方唤醒我们,否则进程不能进入休眠;

3、进程的唤醒

(1)要唤醒进程,前提是要知道哪些进程进入休眠,是因为等待什么资源而进入休眠;
(2)在linux中,维护者一个称为等待队列的数据结构,相当于一个进程链表;将等待同一资源的进程放到同一个等待队列里,将来资源有空闲时就从
相应的等待队列中唤醒一个线程;

4、等待队列

4.1、初始化等待队列

	//静态初始化
	DECLARE_WAIT_QUEUE_HEAD(name) 
 
	//动态方法
	wait_queue_head_t my_queue;
	init_waitqueue_head(&my_queue)		

4.2、将进程添加到等待队列

/*
*wq:等待队列的头,就是上面初始化等待队列得到的;
*condition:条件表达式,当wake_up后,condition为真时,唤醒阻塞的进程
*timeout:超时时间
*/

wait_event(wq, condition);	//进程进入休眠后不能被"ctrl+C"打断
wait_event_timeout(wq, condition, timeout);//进程进入休眠后超时返回
wait_event_interruptible(wq, condition);//进程进入休眠后能被"ctrl+C"打断

(1)举例:wait_event_interruptible(wq, havedata==1);
(2)分析:在进程中执行上面的代码,进程会被加入到wq等待队列中,直到将来被wake_up后,并且havedata==1时才能被唤醒;

4.3、唤醒等待队列中的进程

#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)

#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

上面的两个唤醒函数和添加到等待队列的函数要对应使用,比如wake_up(x)对应wait_event(wq, condition);

5、驱动代码中等待队列的使用

//等待队列头
wait_queue_head_t rwq,wwq; 

//数据缓冲区标志位
int havedata = 0;

static int hello_init(void)
{
	······
	//初始化两个等待队列
	init_waitqueue_head(&rwq); 
	init_waitqueue_head(&wwq); 
	······
}

static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
	int error;

	//此时如果没有准备好数据,则将进程休眠添加到rwq队列,等待唤醒
	wait_event_interruptible(rwq,havedata == 1);
	
	if(size > strlen(kbuf))
	{
		size = strlen(kbuf);
	}

	if(copy_to_user(buf,kbuf, size))
	{
		error = -EFAULT;
		return error;
	}

	//数据被读走,可以写数据
	havedata = 0;

	//唤醒需要写的进程
	wake_up_interruptible(&wwq);

	return size;
}

static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
	int error;
	
	//此时如果没有上次的数据没有被读走,则将进程休眠添加到wwq队列,等待唤醒
	wait_event_interruptible(wwq,havedata == 0);
	
	if(size > KMAX_LEN)
	{
		size = KMAX_LEN;
	}
	memset(kbuf,0,sizeof(kbuf));
	if(copy_from_user(kbuf, buf, size))
	{
		error = -EFAULT;
		return error;
	}
	printk("%s\n",kbuf);
	
	//数据写入,可以读数据
	havedata = 1;
	
	//唤醒需要读的进程
	wake_up_interruptible(&rwq);
	
	return size;
}

上面是摘抄的部分驱动代码,在读写接口中实现休眠和唤醒;

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 08:30:52  更:2022-05-08 08:31:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:40:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码