查看“Semaphore”的源代码
←
Semaphore
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
'''信号量(semaphore)''' 是一种[[:Category:Synchronization|同步]]原始数据类型。 从程序员的角度来看,它是一种不透明的数据类型,有两个定义的操作,通常称为'''wait'''和'''signal'''。(译者注:可以理解为和PV操作对应,wait是P操作-尝试申请资源,signal是V操作-释放资源) 有两种类型的信号量--“二进制信号量”和“计数信号量”。 == 计数信号量 == 最常见的信号量类型是计数信号量。 可以将其视为单个整数变量。 当调用 '''signal''' 方法时,变量被[[atomic operation|原子]] 递增。 当调用'''wait'''方法时,进程将持续等待直到变量达到非零值,然后在返回之前对其进行原子递减。 ==二进制信号量== 二进制信号量 (也称为Mutex-互斥) 就像计数信号量,不同之处在于 '''signal''' 方法将信号量的值设置为1,而不是将其递增。 ==用法== 二进制信号量最常用于保证[[Mutual Exclusion|互斥]]。 在这种情况下,信号量值被初始化为1,并且一个应用程序即将进入代码的互斥部分调用 '''wait''', 然后在退出代码后调用'''signal'''。 计数信号量可以用作实现许多同步模型的构建基础模块。 这方面的典型示例是静态分配的队列,如下面的示例所示。 <source lang="cpp"> Message queue[N]; Semaphore slots = new Semaphore(N); Semaphore messages = new Semaphore(0); int last_read = 0 int last_written = 0; Message get() { Message m; messages.wait(); m = queue[last_read]; last_read = (last_read+1)%N; slots.signal(); return m; } void put(Message m) { slots.wait(); queue[last_written] = m; last_written = (last_written+1)%N; messages.signal(); } </source> 在上面的示例中,这些函数可以使用错误代码来告诉调用方数组何时没有空间,以及队列何时为空 (或断言,由于空间不足而终止程序/使内核崩溃,并试图从空队列中get()内容)。 但是,在许多情况下,您只是希望当前线程阻塞,直到可以执行实际请求为止。 在这些情况下,你需要一个信号量。 有很多(很多很多)算法使用信号量作为同步原语。 当信号量用于同步同一进程的多个线程时,这种算法通常会结合二进制 (互斥) 和计数信号量。 这是因为操纵数据结构的代码仍然必须是互斥的,即使使用信号量来控制资源使用。 == 实现 == 虽然信号量的描述非常简单,但实现并不像最初听起来那样容易。 首先,确保这两种方法原子化运行并不总是容易的; 其次,出于效率的目的,应该从调度器队列中移除对值为0的信号量调用'''wait''' 的线程, 并且只有在信号量发出信号(signalled,译者注:V操作)时才再次添加。 因此,信号量的通常实现是作为内核级对象,它使用另一种更原始的锁定形式(例如[[spinlock|自旋锁]]),以确保一次只能有一个线程访问它。 除了整数变量之外,它还包含一个等待访问的线程队列。 每当调用 '''signal''' 时,在递增变量后立即唤醒并重新安排队列前端的线程 (或者,在某些情况下,变量永远不会递增,唤醒的线程跳过递减的阶段; 这样做可以确保唤醒已有线程进行,而不是某些新到达的线程来抢占)。 每当 '''wait''' 无法立即进行时,当前线程将被挂起并在适当的位置添加到队列中 (例如,在末端,或在与线程优先级正确的位置)。 注意,这里有一个典型的竞争条件,称为lost wake-up(无法唤醒问题)问题。 有关此问题的解决方案,请阅读本文 http://www.linuxjournal.com/article/8144。 ==另见== ===相关文章=== === 论坛主题 === ===外部链接=== * [[wikipedia:Semaphore_(programming)|Semaphore]] on Wikipedia [[Category:Synchronization]] [[Category:IPC]]
返回至“
Semaphore
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息