查看是否该自旋锁的保持者已经释放了锁,“自旋”就是“在原地打转”。而信号量则引起调用者睡眠,它把进程从运行队列上拖出去,除非获得锁。这就是它们的“不类”。但是,无论是信号量,还是自旋锁,在任何时刻,最多只能有一个保持者,即在任何时刻最多只能有一个执行单元获得锁。这就是它们的“类似”。鉴于自旋锁与信号量的上述特点,一般而言,自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用;信号量适合于保持时间较长的情况,会只能在进程上下文使用。如果被保护的共享资源只在进程上下文访问,则可以以信号量来保护该共享资源,如果对共享资源的访问时间非常短,自旋锁也是好的选择。但是,如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。
与信号量相关的
API主要有:
定义信号量
struct semaphore sem;
初始化信号量
void sema_init (struct semaphore *sem, int val);
该函数初始化信号量,并设置信号量
sem的值为 val
void init_MUTEX (struct semaphore *sem); 该函数用于初始化一个互斥锁,即它把信号量 sem的值设置为 1,等同于 sema_init (struct semaphore *sem, 1);
void init_MUTEX_LOCKED (struct semaphore *sem); 该函数也用于初始化一个互斥锁,但它把信号量 sem的值设置为 0,等同于 sema_init (struct semaphore *sem, 0);
获得信号量
void down(struct semaphore * sem); 该函数用于获得信号量 sem,它会导致睡眠,因此不能在中断上下文使用;
int down_interruptible(struct semaphore * sem);
该函数功能与 down类似,不同之处为, down不能被信号打断,但 down_interruptible能被信号打断;
int down_trylock(struct semaphore * sem);
该函数尝试获得信号量 sem,如果能够立刻获得,它就获得该信号量并返回 0,否则,返回非 0值。它不会导致调用者睡眠,可以在中断上下文使用。
释放信号量
void up(struct semaphore * sem); 该函数释放信号量 sem,唤醒等待者。与自旋锁相关的 API主要有:
定义自旋锁
spinlock_t spin;
初始化自旋锁
spin_lock_init(lock) 该宏用于动态初始化自旋锁 lock
获得自旋锁
spin_lock(lock) 该宏用于获得自旋锁 lock,如果能够立即获得锁,它就马上返回,否则,它将自旋在那里,直到该自旋锁的保持者释放;
spin_trylock(lock) 该宏尝试获得自旋锁 lock,如果能立即获得锁,它获得锁并返回真,否则立即返回假,实际上不再“在原地打转”;
释放自旋锁
spin_unlock(lock) 该宏释放自旋锁 lock,它与 spin_trylock或 spin_lock配对使用;除此之外,还有一组自旋锁使用于中断情况下的 API。
//bingfa.c
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define MAJOR_NUM 265
static ssize_t bingfa_read(struct file *, char *, size_t, loff_t*);
static ssize_t bingfa_write(struct file *, const char *, size_t, loff_t*);
static int bingfa_open(struct inode *inode, struct file *filp);
static int bingfa_release(struct inode *inode, struct file *filp);
struct file_operations bingfa_fops =
{
read: bingfa_read, write: bingfa_write, open: bingfa_open, release:
bingfa_release,
};
static int global_var = 0;
static int bingfa_count = 0;
static struct semaphore sem;
static spinlock_t spin = SPIN_LOCK_UNLOCKED;
static int __init bingfa_init(void)
{
int ret;
ret = register_chrdev(MAJOR_NUM, "bingfa", &bingfa_fops);
if (ret)
{
printk("bingfa register failure");
}
else
{
printk("bingfa register success");
init_MUTEX(&sem);
}
return ret;
}
static void __exit bingfa_exit(void)
{
unregister_chrdev(MAJOR_NUM, "bingfa");
}
static int bingfa_open(struct inode *inode, struct file *filp)
//获得自选锁
spin_lock(&spin);
//临界资源访问
if (bingfa_count)
{
spin_unlock(&spin);
return -EBUSY;
}
bingfa_count++;
//释放自选锁
spin_unlock(&spin);
return 0;
}
static int bingfa_release(struct inode *inode, struct file *filp)
{
bingfa_count--;
return 0;
}
static ssize_t bingfa_read(struct file *filp, char *buf, size_t len, loff_t
*off)
{
if (down_interruptible(&sem))
{
return -ERESTARTSYS;
}
if (copy_to_user(buf, &global_var, sizeof(int)))
{
up(&sem);
return -EFAULT;
}
up(&sem);
return sizeof(int);
}
//
static ssize_t bingfa_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
if (down_interruptible(&sem))
{
return -ERESTARTSYS;
}
if (copy_from_user(&global_var, buf, sizeof(int)))
{
up(&sem);
return -EFAULT;
}
up(&sem);
return sizeof(int);
}
module_init(bingfa_init);
module_exit(bingfa_exit);
//测试代码chardev_test.c
#include
#include
#include
#include
main()
{
int fd, num;
//打开“/dev/bingfa”
fd = open("/dev/bingfa", O_RDWR, S_IRUSR | S_IWUSR);
if (fd != -1 )
{
//
//
//初次读 bingfa
read(fd, &num, sizeof(int));
printf("The bingfa is %d\n", num);
//写bingfa
printf("Please input the num written to bingfa\n");
scanf("%d", &num);
write(fd, &num, sizeof(int));
//
//
// //再次读 bingfa
read(fd, &num, sizeof(int));
printf("The bingfa is %d\n", num);
//
//
// //关闭“/dev/bingfa”
//
close(fd);
}
else
{
//
//
printf("Device open failure\n");
}
}
测试结果:[attach]38762[/attach]


Oracleust 于 2012-08-09 21:34:08发表:
强人
半步天涯 于 2012-08-09 18:19:06发表:
哇塞,目前看不懂。 慢慢学吧。