进程间通信之信号量semaphore--linux内核剖析( 三 )


ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off){ //获得信号量 if (down_interruptible( } //将用户空间的数据复制到内核空间的global_var if (copy_from_user(return - EFAULT; } //释放信号量 up( return sizeof(int);}读-写信号量跟自旋锁一样 , 信号量也有区分读-写信号量之分
如果一个读写信号量当前没有被写者拥有并且也没有写者等待读者释放信号量 , 那么任何读者都可以成功获得该读写信号量;
否则 , 读者必须被挂起直到写者释放该信号量 。 如果一个读写信号量当前没有被读者或写者拥有并且也没有写者等待该信号量 , 那么一个写者可以成功获得该读写信号量 , 否则写者将被挂起 , 直到没有任何访问者 。 因此 , 写者是排他性的 , 独占性的 。
读写信号量有两种实现 , 一种是通用的 , 不依赖于硬件架构 , 因此 , 增加新的架构不需要重新实现它 , 但缺点是性能低 , 获得和释放读写信号量的开销大;另一种是架构相关的 , 因此性能高 , 获取和释放读写信号量的开销小 , 但增加新的架构需要重新实现 。 在内核配置时 , 可以通过选项去控制使用哪一种实现 。读写信号量的相关API有:
DECLARE_RWSEM(name)该宏声明一个读写信号量name并对其进行初始化 。
void init_rwsem(struct rw_semaphore *sem);该函数对读写信号量sem进行初始化 。
void down_read(struct rw_semaphore *sem);读者调用该函数来得到读写信号量sem 。 该函数会导致调用者睡眠 , 因此只能在进程上下文使用 。
int down_read_trylock(struct rw_semaphore *sem);该函数类似于down_read , 只是它不会导致调用者睡眠 。 它尽力得到读写信号量sem , 如果能够立即得到 , 它就得到该读写信号量 , 并且返回1 , 否则表示不能立刻得到该信号量 , 返回0 。 因此 , 它也可以在中断上下文使用 。
void down_write(struct rw_semaphore *sem);写者使用该函数来得到读写信号量sem , 它也会导致调用者睡眠 , 因此只能在进程上下文使用 。
int down_write_trylock(struct rw_semaphore *sem);该函数类似于down_write , 只是它不会导致调用者睡眠 。 该函数尽力得到读写信号量 , 如果能够立刻获得 , 就获得该读写信号量并且返回1 , 否则表示无法立刻获得 , 返回0 。 它可以在中断上下文使用 。
void up_read(struct rw_semaphore *sem);读者使用该函数释放读写信号量sem 。 它与down_read或down_read_trylock配对使用 。 如果down_read_trylock返回0 , 不需要调用up_read来释放读写信号量 , 因为根本就没有获得信号量 。
void up_write(struct rw_semaphore *sem);写者调用该函数释放信号量sem 。 它与down_write或down_write_trylock配对使用 。 如果down_write_trylock返回0 , 不需要调用up_write , 因为返回0表示没有获得该读写信号量 。
void downgrade_write(struct rw_semaphore *sem);该函数用于把写者降级为读者 , 这有时是必要的 。 因为写者是排他性的 , 因此在写者保持读写信号量期间 , 任何读者或写者都将无法访问该读写信号量保护的共享资源 , 对于那些当前条件下不需要写访问的写者 , 降级为读者将 , 使得等待访问的读者能够立刻访问 , 从而增加了并发性 , 提高了效率 。读写信号量适于在读多写少的情况下使用 , 在linux内核中对进程的内存映像描述结构的访问就使用了读写信号量进行保护 。究竟什么时候使用自旋锁什么时候使用信号量 , 下面给出建议的方案 当对低开销、短期、中断上下文加锁 , 优先考虑自旋锁;当对长期、持有锁需要休眠的任务 , 优先考虑信号量 。
POSIX信号量详解无名信号量无名信号量的创建就像声明一般的变量一样简单 , 例如:sem_t sem_id 。 然后再初始化该无名信号量 , 之后就可以放心使用了 。
无名信号量常用于多线程间的同步 , 同时也用于相关进程间的同步 。 也就是说 , 无名信号量必须是多个进程(线程)的共享变量 , 无名信号量要保护的变量也必须是多个进程(线程)的共享变量 , 这两个条件是缺一不可的 。
常见的无名信号量相关函数int sem_init(sem_t *sem, int pshared, unsigned int value);

  • pshared==0 用于同一多线程的同步;
  • 若pshared>0 用于多个相关进程间的同步(即由fork产生的)
int sem_getvalue(sem_t *sem, int *sval);取回信号量sem的当前值 , 把该值保存到sval中 。若有1个或更多的线程或进程调用sem_wait阻塞在该信号量上 , 该函数返回两种值: