linux 信号量使用实例

信号量是一种睡眠锁。它是实现同步操作,防止竟态的方式之一。任何进程在对共享数据进行读写操作之前必须获得用来保护共享数据的信号量,否则不能供访问权限,信号量会把这个访问进程放进一个等待队列中(这个等待队列是在信号量初始化过程中被初始化的),然后让其进入睡眠状态。这是处理器重新调度,去执行其他进程的操作。保护共享数据的信号量被释放,被这个信号量放进等待队列的进程会被激活,获得该信号量,然后对共享数据进行访问。

下面的代码演示了在设备驱动程序的读写操作中,信号量的使用
#include #include #include #include #include #include MODULE_LICENSE("GPL"); #define MAJOR_NUM 254 static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*); static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*); struct file_operations globalvar_fops = { read: globalvar_read, write: globalvar_write, }; static int global_var = 0; static struct semaphore sem; static wait_queue_head_t outq; static int flag = 0; static int __init globalvar_init(void) { int ret; ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops); if (ret) { printk("globalvar register failure"); } else { printk("globalvar register success"); init_MUTEX(&sem); //初始化一个互斥锁,即它把信号量sem的值设置为1   init_waitqueue_head(&outq); //初始化等待队列outq } return ret; } static void __exit globalvar_exit(void) { int ret; ret = unregister_chrdev(MAJOR_NUM, "globalvar"); if (ret) { printk("globalvar unregister failure"); } else { printk("globalvar unregister success"); } } //读设备 static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off) { //等待数据可获得 if (wait_event_interruptible(outq, flag != 0)) // wait_event_interruptible把进程状态设为TASK_INTERRUPTIBLE,nonexclusive  { return - ERESTARTSYS; } if (down_interruptible(&sem)) //获得信号量,相当于获得锁 { return - ERESTARTSYS; } flag = 0; if (copy_to_user(buf, &global_var, sizeof(int))) { up(&sem); //如果读取失败,则释放信号量,相当于释放锁 return - EFAULT; } up(&sem); //若读取成功也释放信号量 return sizeof(int); } //写设备 static ssize_t globalvar_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); //写成功后,也释放信号量 flag = 1; wake_up_interruptible(&outq); //唤醒等待进程,通知已经有数据可以读取  return sizeof(int); } module_init(globalvar_init); module_exit(globalvar_exit);

你可能感兴趣的:(linux 信号量使用实例)