Linux Kernel 学习笔记8:同步与互斥之信号量

(本章基于: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

#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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stone8761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值