Linux Kernel 学习笔记8:同步与互斥之信号量
2017-05-04 21:18
375 查看
(本章基于:Linux-4.4.0-37)
内核中信号量的概念与应用层一致,本质是一个整数值,表示当前资源数量。可对这个值进行PV操作。P操作表示如果此信号量大于0,则将信号量减一,进程继续,反之如果信号量小于等于0则等待,等到信号量变为正值,即其他进程释放资源。V操作释放资源,即将信号量值加一,并在必要的时候唤醒正在等待的进程。
当信号量资源数量为1时,其实质就是一个互斥体,这与之前提到的自旋锁非常相似。区别是信号量在无法获取资源时会睡眠等待,释放CPU,而自旋锁不会。因此自旋锁只适用于多核处理器或抢占式内核系统,并且在临界区中不能有可能导致睡眠的操作。在其他情况下,信号量是最佳选择。
信号量数据结构 linux/semaphore.h
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
static inline void sema_init(struct semaphore *sem, int val);
初始化一个信号量,val表示初始资源个数
在linux内核中P操作被称为down,内核中有多种down操作
extern void down(struct semaphore *sem);
不可中断down,谨慎使用,如果获取不到资源进程将无法中断,无法被kill
extern int __must_check down_interruptible(struct semaphore *sem);
可中断down,最常用
extern int __must_check down_killable(struct semaphore *sem);
可被致命信号唤醒
extern int __must_check down_trylock(struct semaphore *sem);
不睡眠,返回0表示获取到信号量,返回1表示未获取
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
限制睡眠时间,返回0表示成功获取信号量
V被称之为up操作
extern void up(struct semaphore *sem);
例:
sema.c
应用层:
a.c
内核中信号量的概念与应用层一致,本质是一个整数值,表示当前资源数量。可对这个值进行PV操作。P操作表示如果此信号量大于0,则将信号量减一,进程继续,反之如果信号量小于等于0则等待,等到信号量变为正值,即其他进程释放资源。V操作释放资源,即将信号量值加一,并在必要的时候唤醒正在等待的进程。
当信号量资源数量为1时,其实质就是一个互斥体,这与之前提到的自旋锁非常相似。区别是信号量在无法获取资源时会睡眠等待,释放CPU,而自旋锁不会。因此自旋锁只适用于多核处理器或抢占式内核系统,并且在临界区中不能有可能导致睡眠的操作。在其他情况下,信号量是最佳选择。
信号量数据结构 linux/semaphore.h
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
static inline void sema_init(struct semaphore *sem, int val);
初始化一个信号量,val表示初始资源个数
在linux内核中P操作被称为down,内核中有多种down操作
extern void down(struct semaphore *sem);
不可中断down,谨慎使用,如果获取不到资源进程将无法中断,无法被kill
extern int __must_check down_interruptible(struct semaphore *sem);
可中断down,最常用
extern int __must_check down_killable(struct semaphore *sem);
可被致命信号唤醒
extern int __must_check down_trylock(struct semaphore *sem);
不睡眠,返回0表示获取到信号量,返回1表示未获取
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
限制睡眠时间,返回0表示成功获取信号量
V被称之为up操作
extern void up(struct semaphore *sem);
例:
sema.c
#include <linux/init.h> #include <linux/module.h> #include <linux/stat.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/cdev.h> #include <asm/uaccess.h> #include <linux/delay.h> #include <linux/semaphore.h> static dev_t devId; static struct class *cls = NULL; static struct cdev myDev; static struct semaphore mySema; static int my_open(struct inode *inode, struct file *file) { int i; while(down_interruptible(&mySema) != 0); for(i=0; i<10; i++) { printk(KERN_WARNING "%d\n", i); ssleep(1); } up(&mySema); printk(KERN_WARNING "open success!\n"); return 0; } static int my_release(struct inode *inode, struct file *file) { printk(KERN_WARNING "close success!\n"); return 0; } //定义文件操作 static struct file_operations myFops = { .owner = THIS_MODULE, .open = my_open, .release = my_release, }; static void hello_cleanup(void) { cdev_del(&myDev); device_destroy(cls, devId); class_destroy(cls); unregister_chrdev_region(devId, 1); } static __init int hello_init(void) { int result; sema_init(&mySema, 1); //动态注册设备号 if(( result = alloc_chrdev_region(&devId, 0, 1, "stone-alloc-dev") ) != 0) { printk(KERN_WARNING "register dev id error:%d\n", result); goto err; } else { printk(KERN_WARNING "register dev id success!\n"); } //动态创建设备节点 cls = class_create(THIS_MODULE, "stone-class"); if(IS_ERR(cls)) { printk(KERN_WARNING "create class error!\n"); goto err; } if(device_create(cls, NULL, devId, "", "hello%d", 0) == NULL) { printk(KERN_WARNING "create device error!\n"); goto err; } //字符设备注册 myDev.owner = THIS_MODULE; //必要的成员初始化 myDev.ops = &myFops; cdev_init(&myDev, &myFops); //添加一个设备 result = cdev_add(&myDev, devId, 1); if(result != 0) { printk(KERN_WARNING "add cdev error!\n"); goto err; } printk(KERN_ALERT "hello init success!\n"); return 0; err: hello_cleanup(); return -1; } static __exit void hello_exit(void) { hello_cleanup(); printk(KERN_WARNING "helloworld exit!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stone");
应用层:
a.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(void) { int fd; char buf[100]; int size; fd = open("/dev/hello0", O_RDWR); if(!fd) { perror("open"); exit(-1); } printf("open success!\n"); close(fd); return 0; }
相关文章推荐
- Linux Kernel 学习笔记7:同步与互斥之自旋锁
- 操作系统学习笔记(8) 互斥和同步的实现算法
- “单比特信号同步” 学习笔记(跨时钟域问题)
- linux 系统编程-学习笔记9--线程的同步互斥锁、读写锁/select/poll
- 操作系统学习笔记(10) 互斥和同步的经典问题
- 操作系统学习笔记(13) 互斥与同步的经典问题 -哲学家进餐问题
- “单比特信号同步” 学习笔记
- uc/os-iii学习笔记-资源管理(中断、信号、信号量、互斥信号量)
- 学习笔记 --- LINUX的同步互斥机制 --- 自旋锁与信号量的区别
- 操作系统学习笔记(9) 互斥和同步的信号量算法
- linux c语言学习笔记之IPC-信号
- Unix信号处理学习笔记
- Java6学习笔记57——多线程编程——线程的互斥(version 0.2)
- 【学习笔记】dataGridView 滚动条同步
- SilverLight学习笔记--实际应用(一)(4):手把手建立一个Silverlight应用程序之同步数据校验1
- Linux Kernel学习笔记
- Unix信号处理学习笔记
- [原创]W2k Driving 学习笔记(一)内核线程及同步
- 孙鑫VC学习笔记:第十五讲 (三) 增加互斥条件实现线程同步
- OpenCV学习笔记(6)基于 VC+OpenCV+DirectShow 的多个摄像头同步工作