互斥体用于控制进程对临界资源的访问,属于进程级别,互斥体保护的临界区可以包含能够引起进程阻塞的代码。
1. 互斥体的定义及初始化
struct mutex mutex; //定义
mutex_init(&mutex); //初始化
2. 获取互斥体
void mutex_lock(struct mutex *lock); //获取互斥体,不能被信号打断。
int mutex_lock_interruptible(struct mutex *lock); //获取互斥体,能被信号打断。
int mutex_trylock(struct mutex *lock); //不阻塞,立即返回。
3. 释放互斥体
void mutex_unlock(struct mutex *lock); //释放互斥体
4. 使用互斥体的具体实例:
/*
* g_mtex.c
*
* Created on: 2016年11月21日
* Author: chy
*/
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fcntl.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#define Buff_size 1024
#define dev_num 2
struct g_mutex{
struct mutex mutex;
char *buff;
};
struct g_mutex *g_buf = NULL;
static int open_file(struct inode *node,struct file *g_file)
{
int ret = 1;
int minor = MINOR(node->i_rdev);
if(minor < dev_num){
g_file->private_data = &g_buf[minor];
ret = 0;
}
printk(KERN_INFO"打开文件\n");
return ret;
}
static int close_file(struct inode *node,struct file *g_file)
{
return 0;
}
static ssize_t read_file(struct file *g_file,char __user *buf,size_t size,loff_t *offt)
{
int ret;
loff_t ops = *offt;
struct g_mutex *mutex = g_file->private_data;
size_t count = size;
if(ops >= strlen(mutex->buff) || ops >= Buff_size)
return -1;
if(ops + count > strlen(mutex->buff))
count = strlen(mutex->buff) - ops;
mutex_lock(&mutex->mutex); //获得互斥锁
if(copy_to_user(buf,mutex->buff + ops,count))
ret = -EFAULT;
else{
*offt += count;
ret = count;
}
mutex_unlock(&mutex->mutex); //释放互斥锁
return ret;
}
static ssize_t write_file(struct file *g_file,const char __user *buf,size_t size,loff_t* offt)
{
int ret;
loff_t ops = *offt;
struct g_mutex *mutex = g_file->private_data;
size_t count = size;
if(ops >= Buff_size)
return -1;
if(Buff_size - ops > strlen(buf))
count = strlen(buf);
else count = Buff_size - ops;
mutex_lock(&mutex->mutex); //获得互斥锁
if(copy_from_user(mutex->buff + ops,buf,count)) //复制到用户区
ret = -EFAULT;
else{
*offt += count;
ret = count;
}
mutex_unlock(&mutex->mutex); //释放互斥锁
return ret;
}
static long g_ioctl(struct file *g_file,unsigned cmd,unsigned long ctl)
{
struct g_mutex *mutex = g_file->private_data;
switch(cmd){
case 0:
mutex_lock(&mutex->mutex); //获取互斥锁
memset(mutex->buff, 0,sizeof(char) * Buff_size);
mutex_unlock(&mutex->mutex); //释放互斥锁
break;
default:
return -EINVAL;
}
return 0;
}
struct file_operations file_ops = {
.owner = THIS_MODULE,
.open = open_file,
.release = close_file,
.read = read_file,
.write = write_file,
.unlocked_ioctl = g_ioctl,
};
struct cdev dev = {
.owner = THIS_MODULE,
};
dev_t dev_no;
struct class *dev_class = NULL;
static int g_mutex_init(void)
{
int ret = 0;
int i;
ret = alloc_chrdev_region(&dev_no,0,dev_num,"g_mutex"); //申请设备号
if(ret < 0)
return ret;
cdev_init(&dev,&file_ops); //初始化设备
cdev_add(&dev,dev_no,dev_num); //向内核注册设备
g_buf = (struct g_mutex *)kmalloc(sizeof(struct g_mutex) * dev_num,GFP_KERNEL); //为虚拟设备分配内存
if(!g_buf){
printk(KERN_INFO "内存分配失败\n");
unregister_chrdev_region(dev_no,dev_num);
return -ENOMEM;
}
for(i = 0; i < dev_num; i++){
g_buf[i].buff = (char *)kmalloc(sizeof(char) * Buff_size,GFP_KERNEL);
memset(g_buf[i].buff,0,sizeof(char) * Buff_size);
mutex_init(&(g_buf[i].mutex)); //初始化互斥变量
}
/*创建设备文件*/
dev_class = class_create(THIS_MODULE,"mutex_device");
device_create(dev_class,0,MKDEV(MAJOR(dev_no),0),0,"mutex_dev_0");
device_create(dev_class,0,MKDEV(MAJOR(dev_no),1),0,"mutex_dev_1");
printk(KERN_INFO"加载\n");
return ret;
}
static void g_mutex_exit(void)
{
int i;
cdev_del(&dev); //删除cdev
for(i = 0; i < dev_num; i++)
kfree(g_buf[i].buff);
kfree(g_buf); //释放内存
/*删除设备文件*/
device_destroy(dev_class, MKDEV(MAJOR(dev_no),0));
device_destroy(dev_class, MKDEV(MAJOR(dev_no),1));
class_destroy(dev_class);
unregister_chrdev_region(dev_no,dev_num); //释放设备号
printk(KERN_INFO"卸载\n");
return;
}
MODULE_LICENSE("GPL v2");
module_init(g_mutex_init);
module_exit(g_mutex_exit);//卸载