查看“︁監視器 (程序同步化)”︁的源代码
←
監視器 (程序同步化)
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
{{noteTA |T=zh-cn:管程; zh-tw:監視器 (程序同步化); |G1=IT |1=zh-cn:管程;zh-tw:監視器; }} '''監視器''' ({{lang-en|Monitors}},也称为'''-{zh-cn:监视器; zh-tw:管程;}-''') 是一种程序结构,结构内的多个子程序([[对象 (计算机科学)|对象]]或[[模組 (程式設計)|模块]])形成的多个[[工作 (資訊科學)|工作线程]]互斥访问共享資源。這些共享資源一般是[[硬體裝置|硬件]]或一群[[變數]]。管程实现了在一个时间点,最多只有一个[[线程]]在执行管程的某个[[子程序]]。与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。 管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。 管程是[[東尼·霍爾|东尼·霍尔]] <ref>Hoare, C. A. R. (1974), "Monitors: an operating system structuring concept". Comm. A.C.M. '''17(10)''', 549–57. [http://doi.acm.org/10.1145/355620.361161] </ref> 与[[泊·派克·漢森]] <ref>Brinch Hansen, P. (1975). "The programming language Concurrent Pascal". IEEE Trans. Softw. Eng. '''2''' (June), 199–206. </ref>提出的,并由泊·派克·漢森首次在[[并行Pascal]]中实现。东尼·霍尔证明了這與[[信号量]]是等價的。管程在当时也被用于[[單作業系統]]环境中的[[进程]]間通訊。 在程式語言{{tsl|en|Concurrent Pascal|}},[[Pascal-Plus]],[[Modula-2]],[[Modula-3]],[[Mesa语言|Mesa]]以及[[Java]]中都提供這個功能。 == 管程实现对共享资源的互斥访问 == 一個監視器包含: * 多个彼此可以交互並共用資源的[[线程]] * 多个與資源使用有關的變數 * 一個[[互斥锁|互斥鎖]] * 一個用來避免[[競爭危害|竞态条件]]的[[不變量]] 一個監視器的程序在執行一个线程前會先取得互斥鎖,直到完成线程或是线程等待某个條件被满足才會放弃互斥锁。若每個执行中的线程在放弃互斥鎖之前都能保證不變量成立,則所有线程皆不會導致竞态条件成立。 以下這個银行账户的提款/存款事务的監視器是個簡單的例子: '''monitor class''' ''Account'' { '''private''' ''int'' balance := 0 '''invariant''' balance >= 0 '''public method''' ''boolean'' withdraw(''int'' amount) '''precondition''' amount >= 0 { '''if''' balance < amount '''then''' '''return false''' '''else''' { balance := balance - amount ; '''return true''' } } '''public method''' deposit(''int'' amount) '''precondition''' amount >= 0 { balance := balance + amount } } 当一个线程执行管程中的一个子程序时,称为占用(occupy)该管程. 管程的实现确保了在一个时间点,最多只有一个线程占用了该管程。这是管程的互斥锁访问性质。 当线程要调用一个定义在管程中的子程序时,必须等到已经没有其它线程在执行管程中的某个子程序。 在管程的简单实现中,[[編譯器]]为每个管程对象自動加入一把私有的互斥锁。该互斥锁初始状态为解锁,在管程的每个公共子程序的入口给该互斥锁加锁,在管程的每个公共子程序的出口给该互斥锁解锁。 這個例子中的[[不变条件|不變量]]是「任何操作執行前 balance 變數必須反映正確的餘額」。一般而言,不變量的條件不被寫在程式中,而在[[注释 (计算机语言)|註解]]中有相關說明,然而[[Eiffel|Eiffel程序设计语言]]显式檢查不變量。 == 條件變數(Condition Variable) == 对于许多应用场合,互斥操作是不够用的。线程可能需要等待某个条件<math>P</math>为真,才能继续执行。在一个[[忙碌等待]]循环中 '''while''' '''not'''( <math>P</math> ) '''do''' '''skip''' 将会导致所有其它进程都无法进入[[临界区]]使得该条件<math>P</math>为真,该管程发生[[死锁]]. 解决办法是'''条件变量'''(condition variables). 概念上,一个条件变量就是一个线程队列(queue), 其中的线程正等待某个条件变为真。每个条件变量<math>c</math>关联着一个[[斷言 (程式)|断言]]<math>P_c</math>. 当一个线程等待一个条件变量,该线程不算作占用了该管程,因而其它线程可以进入该管程执行,改变管程的状态,通知条件变量<math>c</math>其关联的断言<math>P_c</math>在当前状态下为真. 因此对条件变量存在两种主要操作: * <code>'''wait''' c </code>被一个线程调用,以等待断言<math>P_c</math>被满足后该线程可恢复执行. 线程挂在该条件变量上等待时,不被认为是占用了管程. * <code>'''signal''' c </code> (有时写作<code>'''notify''' c</code>)被一个线程调用,以指出断言<math>P_c</math>现在为真. 在下述例子中, 用管程实现了一个[[信号量]]. 一个私有整型变量<code>s</code>需要被互斥访问。管程中定义了子程序“增加”(V)与子程序“减少”(P),整型变量<code>s</code>不能被减少到小于0; 因此子程序“减少”必须等到该整型变量是正数时才可执行. 使用条件变量<code>sIsPositive</code>与相关联的断言<math> P_{sIsPositive} = (s > 0)</math>. '''monitor class''' ''Semaphore'' { '''private''' ''int'' s := 0 '''invariant''' s >= 0 '''private''' ''Condition'' sIsPositive /* '''associated with''' s > 0 */ '''public method''' P() { '''if''' s = 0 '''then''' '''wait''' sIsPositive '''assert''' s > 0 s := s - 1 } '''public method''' V() { s := s + 1 '''assert''' s > 0 '''signal''' sIsPositive } } 当一个通知(signal)发给了一个有线程处于等待中的条件变量,则有至少两个线程将要占用该管程: 发出通知的线程与等待该通知的某个线程. 只能有一个线程占用该管程,因此必须做出选择。两种理论体系导致了两种不同的条件变量的实现: * 阻塞式条件变量(Blocking condition variables),把优先级给了被通知的线程. * 非阻塞式条件变量(Nonblocking condition variables),把优先级给了发出通知的线程. ===阻塞式条件变量=== 东尼·霍尔与泊·派克·汉森最早提出的是阻塞式条件变量. 发出通知(signaling)的线程必须等待被通知(signaled)的线程放弃占用管程(或者离开管程,或者等待某个条件变量)。使用阻塞式条件变量的管程被称为''霍尔风格''(Hoare-style)管程或''通知且急迫等待''(signal-and-urgent-wait)管程. [[Image:Monitor (synchronization)-SU.png|thumb|300px|right|霍尔风格管程,有两个条件变量<code>a</code>与<code>b</code>. 根据Buhr ''et al.'']] 设每个管程对象有两个线程队列 * <code>e</code>是入口队列 * <code>s</code>是已经发出通知的线程队列. 设对于每个条件变量<math>c</math>, 有一个线程队列 * <code><math>c</math>.q</code>, 所有等待<math>c</math>的线程的队列 这些队列会公平(fair)调度,甚至实现为[[先進先出|先进先出]]. 各个环节实现如下 (规定各个环节彼此是互斥的. 因此restart一个线程,并不会立即执行,直到当前环节完成) enter the monitor: enter the method if the monitor is locked add this thread to e block this thread else lock the monitor leave the monitor: schedule return from the method '''wait''' <math>c</math> : add this thread to <math>c</math>.q schedule block this thread '''signal''' <math>c</math> : if there is a thread waiting on <math>c</math>.q select and remove one such thread t from <math>c</math>.q (t is called "the signaled thread") add this thread to s restart t (so t will occupy the monitor next) block this thread schedule : if there is a thread on s select and remove one thread from s and restart it (this thread will occupy the monitor next) else if there is a thread on e select and remove one thread from e and restart it (this thread will occupy the monitor next) else unlock the monitor (the monitor will become unoccupied) <code>schedule</code>子程序选择下一个线程占用管程,如果没有候选的线程则解锁管程. 发出通知的线程转入等待,但会比在线程入口的队列有更高优先权被调度,这称为''"通知且急迫等待"''。另一种方案是''"通知且等待"'',不设<code>s</code>队列,发出通知的线程进入<code>e</code>队列等待. 某些实现提供了'''signal and return'''操作. '''signal''' <math>c</math> '''and return''' : if there is a thread waiting on <math>c</math>.q select and remove one such thread t from <math>c</math>.q (t is called "the signaled thread") restart t (so t will occupy the monitor next) else schedule return from the method 如果在每个'''signal''' <math>c</math>的开始处,<math>P_c</math>为真, 那么在'''wait''' <math>c</math>的结尾处<math>P_c</math>也应为真。 这可由[[契约式设计]]来表达. 在这些契约中, <math>I</math>是管程的不变量. enter the monitor: '''postcondition''' <math>I</math> leave the monitor: '''precondition''' <math>I</math> '''wait''' <math>c</math> : '''precondition''' <math>I</math> '''modifies''' the state of the monitor '''postcondition''' <math>P_c</math> and <math>I</math> '''signal''' <math>c</math> : '''precondition''' <math>P_c</math> and <math>I</math> '''modifies''' the state of the monitor '''postcondition''' <math>I</math> '''signal''' <math>c</math> '''and return''' : '''precondition''' <math>P_c</math> and <math>I</math> 在上述契约中,设定<math>I</math> and <math>P_c</math>不依赖于任何队列长度. 如果可以查询条件变量所关联的队列上处于等待的线程的数量,可以使用更为复杂的契约。例如,一个有用的契约对,无需不变量就允许管程的占用被传递 '''wait''' <math>c</math> : '''precondition''' <math>I</math> '''modifies''' the state of the monitor '''postcondition''' <math>P_c</math> '''signal''' <math>c</math> '''precondition''' ('''not''' empty(<math>c</math>) '''and''' <math>P_c</math>) '''or''' (empty(<math>c</math>) '''and''' <math>I</math>) '''modifies''' the state of the monitor '''postcondition''' <math>I</math> 参见 Howard<ref name="Howard76">John Howard (1976), "Signaling in monitors". ''Proceedings of the 2nd International Conference on Software Engineering'', 47–52</ref> and Buhr ''et al.,''<ref name="Buhr95">Buhr, P.H; Fortier, M., Coffin, M.H. (1995). "Monitor classification". ACM Computing Surveys (CSUR) '''27(1)'''. 63–107. [http://doi.acm.org/10.1145/214037.214100]</ref>有更多信息。 特别需要注意,断言<math>P_c</math>完全是由编程者负责,编程者需要在头脑中保持对断言有一致的(consistent)定义。 下例是用阻塞式管程实现一个有界的、[[线程安全]]的[[堆栈|栈]]. 即多线程并发访问这个栈时,在任意时刻最多只有一个线程执行push或pop操作。 '''monitor class''' ''SharedStack'' { '''private const''' capacity := 10 '''private''' ''int''[capacity] A '''private''' ''int'' size := 0 '''invariant''' 0 <= size '''and''' size <= capacity '''private''' ''BlockingCondition'' theStackIsNotEmpty /* '''associated with''' 0 < size '''and''' size <= capacity */ '''private''' ''BlockingCondition'' theStackIsNotFull /* '''associated with''' 0 <= size '''and''' size < capacity */ '''public method''' push(''int'' value) { '''if''' size = capacity '''then''' '''wait''' theStackIsNotFull '''assert''' 0 <= size '''and''' size < capacity A[size] := value ; size := size + 1 '''assert''' 0 < size '''and''' size <= capacity '''signal''' theStackIsNotEmpty '''and return''' } '''public method''' ''int'' pop() { '''if''' size = 0 '''then''' '''wait''' theStackIsNotEmpty '''assert''' 0 < size '''and''' size <= capacity size := size - 1 ; '''assert''' 0 <= size '''and''' size < capacity '''signal''' theStackIsNotFull '''and return''' A[size] } } ===非阻塞式条件变量=== ''非阻塞式条件变量'' (也称作''"Mesa风格"''条件变量或''"通知且继续"''(signal and continue)条件变量), 发出通知的线程并不会失去管程的占用权. 被通知的线程将会被移入管程入口的<code>e</code>队列. 不需要<code>s</code>队列。[[pthread]]中的条件变量就是这种非阻塞式:要先显式获得互斥加锁(pthread_mutex_lock),调用pthread_cond_wait时隐式对互斥锁解锁并进入阻塞睡眠,被唤醒后还要再显式获得互斥加锁。 [[Image:Monitor (synchronization)-Mesa.png|thumb|250px|right|Mesa风格的管程,有两个条件变量<code>a</code>与<code>b</code>]] 非阻塞式条件变量经常把'''signal'''操作称作'''notify''' — . 也常用'''notify all'''操作把该条件变量关联的队列上所有的线程移入<code>e</code>队列. 各种操作定义如下. (规定各种操作都是互斥的,线程被restart并不会立即执行,直到发起的操作完成) enter the monitor: enter the method if the monitor is locked add this thread to e block this thread else lock the monitor leave the monitor: schedule return from the method '''wait''' <math>c</math> : add this thread to <math>c</math>.q schedule block this thread '''notify''' <math>c</math> : if there is a thread waiting on <math>c</math>.q select and remove one thread t from <math>c</math>.q (t is called "the notified thread") move t to e '''notify all''' <math>c</math> : move all threads waiting on <math>c</math>.q to e schedule : if there is a thread on e select and remove one thread from e and restart it else unlock the monitor 一个变种实现,把被通知的(notified)线程移入队列<code>w</code>, 具有比<code>e</code>更高的优先级. 参见 Howard<ref name="Howard76"/> and Buhr ''et al.''<ref name="Buhr95"/>。 可以把断言<math>P_c</math>关联于条件变量<math>c</math>,因而<math>P_c</math><code>'''wait''' <math>c</math></code>返回时期望为真. 但是,这必须确保发出通知的线程结束到被通知的线程恢复执行这一时间段内,<math>P_c</math>保持为真. 这一时间段内可能会有其它线程占用过管程。因此通常必须把每个'''wait'''操作用一个循环包裹起来: '''while''' '''not'''( <math>P</math> ) '''do''' '''wait''' c 其中<math>P</math>是一个条件,强于<math>P_c</math>. 操作<code>'''notify''' <math>c</math></code>与<code>'''notify all''' <math>c</math></code>被视为"提示"(hints)某个等待队列的<math>P</math>可能为真. 上述循环的每一次迭代,表示失去了一次通知。 一个银行账户的例子,取款线程将等待资金已经完成注入账户之后再执行。 '''monitor class''' ''Account'' { '''private''' ''int'' balance := 0 '''invariant''' balance >= 0 '''private''' ''NonblockingCondition'' balanceMayBeBigEnough '''public method''' withdraw(''int'' amount) '''precondition''' amount >= 0 { '''while''' balance < amount '''do''' '''wait''' balanceMayBeBigEnough '''assert''' balance >= amount balance := balance - amount } '''public method''' deposit(''int'' amount) '''precondition''' amount >= 0 { balance := balance + amount '''notify all''' balanceMayBeBigEnough } } 在这个例子中,被等待的条件是取款金额大于存款余额,存款线程不可能知道取款金额,因此存款线程发出的通知的意涵是提示所有等待中的取款线程检查它自身的断言是否为真。 ===隐式条件变量管程=== [[Image:Monitor (synchronization)-Java.png|thumb|200px|right|Java风格管程]] [[Java程序设计语言]]中,每个对象都可以作为一个管程。需要互斥使用的方法必须明确标示关键字'''synchronized'''。 代码块也可以标示关键字'''synchronized'''。 不使用明确的条件变量, Java的这种管程在入口队列之外,使用单独的条件等待队列. 所有等待的线程进入这个队列,所有的'''notify'''与'''notify all'''操作也施加于这个队列。这种方法已经被其它程序设计语言使用,如[[C♯|C#]]。 ===隐式通知=== 另一种实现方法是忽略'''signal'''操作。当一个线程交出管程占用权(returning或者waiting),所有处于等待状态的线程的断言都被检查,直到发现某个线程的断言为真。在这种系统中,不需要条件变量,但是断言必须明确编码。 wait操作的契约: '''wait''' <math>P</math>: '''precondition''' <math>I</math> '''modifies''' the state of the monitor '''postcondition''' <math>P</math> and <math>I</math> ===Posix Thread中的条件变量=== [[pthread]]中,条件变量实际上是一个阻塞线程处于睡眠状态的线程队列。每个条件变量都必须与一个(且建议只能是一个)互斥锁配套使用。一个线程首先获得互斥锁,然后检查或者修改“条件”;如果条件不成立,则调用pthread_cond_wait(),依次实施3个操作: #对当前互斥锁解锁(以便其它线程可以访问或者修改“条件”) #把线程自身阻塞挂起到互斥锁的线程队列中 #被其它线程的[[Signal.h|信号]]从互斥锁的线程队列唤醒后,对当前配套的互斥锁申请加锁,如果加锁未能成功,则阻塞挂起到当前互斥锁上。pthread_cond_wait() 函数将不返回直到线程获得配套的互斥锁。 线程离开“条件”的临界区时,必须对当前互斥锁执行解锁。 ===Windows Thread中的条件变量=== 从[[Windows Vista]]开始,Windows Thread用[[critical section]]与条件变量配合,二者均为用户态同步对象,不能跨进程使用。使用API函数InitializeConditionVariable创建条件变量;函数SleepConditionVariableCS用于释放临界区并阻塞在条件变量上;函数WakeConditionVariable或 WakeAllConditionVariable唤醒挂在条件变量上的线程。 也可配套使用[[读写锁]](Slim Reader/Writer (SRW) Locks)。 ===Spurious wakeup=== 假唤醒是POSIX Threads与Windows API使用条件变量时可能发生的复杂情形。一个挂在条件变量上的线程被signaled,正在等待的条件仍有可能不成立。假唤醒(Spurious wakeup)是指即使没有线程signaled该条件变量,挂在该条件变量上的线程却被唤醒。<ref>David R. Butenhof《Programming with POSIX Threads》 ISBN 0-201-63392-2: "This means that when you wait on a condition variable, the wait may (occasionally) return when no thread specifically broadcast or signaled that condition variable. Spurious wakeups may sound strange, but on some multiprocessor systems, making condition wakeup completely predictable might substantially slow all condition variable operations. The race conditions that cause spurious wakeups should be considered rare." </ref>因此,应该用while循环包围条件变量等待操作: <syntaxhighlight lang="c"> /* In any waiting thread: */ while(!buf->full) wait(&buf->cond, &buf->lock); /* In any other thread: */ if(buf->n >= buf->size){ buf->full = 1; signal(&buf->cond); }</syntaxhighlight> ===stolen wakeups=== 被偷走的唤醒是POSIX Threads与Windows API使用条件变量时,线程调用g_cond_signal时,另一个线程已经获取了mutex使得期望的条件不再满足,因此被唤醒的线程面临着条件不成立。<ref>{{Cite web |url=https://msdn.microsoft.com/en-us/library/ms686301(v=vs.85).aspx |title=MSDN:SleepConditionVariableCS function |access-date=2017-02-16 |archive-date=2017-02-16 |archive-url=https://web.archive.org/web/20170216214637/https://msdn.microsoft.com/en-us/library/ms686301(v=vs.85).aspx |dead-url=no }}</ref><ref>{{Cite web |url=http://developer.gnome.org/glib/unstable/glib-Threads.html |title=GNOME DEVELOPER: Threads Functions |access-date=2017-02-16 |archive-date=2020-08-14 |archive-url=https://web.archive.org/web/20200814231810/https://developer.gnome.org/glib/unstable/glib-Threads.html |dead-url=no }}</ref>因此,应该用while循环包围条件变量等待操作. == 历史 == [[東尼·霍爾|东尼·霍尔]]与[[泊·派克·漢森]]在1972年形成了管程的构思, 根据他们自己更早的想法与[[艾兹赫尔·戴克斯特拉]]的工作. <ref>Brinch Hansen, P. (1993). "Monitors and concurrent Pascal: a personal history", ''The second ACM SIGPLAN conference on History of programming languages'' 1–35. Also published in ''ACM SIGPLAN Notices'' '''28(3)''', March 1993. [http://doi.acm.org/10.1145/154766.155361] </ref> 泊·派克·漢森第一个实现了管程。 东尼·霍尔发展了理论框架并证明了与[[信号量]]等价。 管程不久用于单任务操作系统的[[进程间通信]]. 已经支持管程的程序设计语言: {{div col|colwidth=25em}} *[[Ada程序设计语言|Ada]] (从 Ada 95 (作为protected objects) 开始) *[[C♯|C#]] (以及其它使用[[.NET Framework]]的程序设计语言) *[[C++]] (从 [[C++11]] 开始,详见[[b:C++/STL/ConditionVariable]]) *{{tsl|en|Concurrent Euclid|}} *{{tsl|en|Concurrent Pascal|}} *[[D程序设计语言|D]] *[[Delphi]] (Delphi 2009及更高版本,使用TObject.Monitor) *[[Java程序设计语言|Java]] (使用wait与notify methods) *[[Mesa语言|Mesa]] *[[Modula-3]] *[[Python程序设计语言|Python]](通过threading.Condition<ref>[http://docs.python.org/library/threading.html#condition-objects threading.Condition] {{Wayback|url=http://docs.python.org/library/threading.html#condition-objects |date=20121022063138 }}</ref>对象) *[[Ruby]] *[[Squeak]] [[Smalltalk]] *{{tsl|en|Turing (programming language)|Turing}}, {{tsl|en|Turing+|}}与{{tsl|en|Object-Oriented Turing|}} *{{tsl|en|μC++|}} {{div col end}} 许多库已经允许在程序设计语言没有本地支持时构建管程。当库调用时,编程者负责明确表示互斥执行的代码块的开始与结尾. [[POSIX线程|Pthreads]]就是这样一个库. ==参考文献== {{reflist|2}} == 外部链接 == * "[http://www.acm.org/classics/feb96/ Monitors: An Operating System Structuring Concept] {{Wayback|url=http://www.acm.org/classics/feb96/ |date=20060830171518 }}" by [[Charles Antony Richard Hoare]] * "[http://portal.acm.org/citation.cfm?id=807647 Signalling in Monitors]" by [[John H. Howard]] * "[http://portal.acm.org/citation.cfm?id=358824 Experience with Processes and Monitors in Mesa] {{Wayback|url=http://portal.acm.org/citation.cfm?id=358824 |date=20200312195920 }}" by [[Butler W. Lampson]] and [[David D. Redell]] * [http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cond_wait.html pthread_cond_wait] {{Wayback|url=http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cond_wait.html |date=20101209231431 }} - description from the Open Group Base Specifications Issue 6, IEEE Std 1003.1 * "[https://web.archive.org/web/20070311234034/http://gd.tuwien.ac.at/languages/c/programming-dmarshall/node31.html#SECTION003125000000000000000 Block on a Condition Variable]" by [[Dave Marshall]] * "[https://web.archive.org/web/20060909103157/http://www.cs.wustl.edu/%7Eschmidt/win32-cv-1.html Strategies for Implementing POSIX Condition Variables on Win32]" by [[Douglas C. Schmidt]] and [[Irfan Pyarali]] * [http://apr.apache.org/docs/apr/group__apr__thread__cond.html Condition Variable Routines] {{Wayback|url=http://apr.apache.org/docs/apr/group__apr__thread__cond.html |date=20030629081546 }} from the [[Apache Portable Runtime]] Library * [http://wxwidgets.org/manuals/2.6.3/wx_wxcondition.html wxCondition description] {{Wayback|url=http://wxwidgets.org/manuals/2.6.3/wx_wxcondition.html |date=20070523145808 }} * [https://web.archive.org/web/20070307134532/http://www.boost.org/doc/html/condition.html boost::condition class description] * [http://zthread.sourceforge.net/html/classZThread_1_1Condition.html ZThread Condition Class Reference] {{Wayback|url=http://zthread.sourceforge.net/html/classZThread_1_1Condition.html |date=20161229104938 }} * [http://wefts.sourceforge.net/wefts-apidoc-0.99c/classWefts_1_1Condition.html Wefts::Condition Class Reference] {{Wayback|url=http://wefts.sourceforge.net/wefts-apidoc-0.99c/classWefts_1_1Condition.html |date=20161229110558 }} * [https://web.archive.org/web/20060401000533/http://www.dre.vanderbilt.edu/Doxygen/Stable/ace/classACE__Condition.html ACE_Condition Class Template Reference] * [https://web.archive.org/web/20070209132642/http://doc.trolltech.com/4.0/qwaitcondition.html QWaitCondition Class Reference] * [http://www.gnu.org/software/commoncpp/docs/refman/html/class_conditional.html Common C++ Conditional Class Reference] {{Wayback|url=http://www.gnu.org/software/commoncpp/docs/refman/html/class_conditional.html |date=20100201072822 }} * [http://austria.sourceforge.net/dox/html/classat_1_1ConditionalMutex.html at::ConditionalMutex Class Reference] {{Wayback|url=http://austria.sourceforge.net/dox/html/classat_1_1ConditionalMutex.html |date=20120204060528 }} * [http://perldoc.perl.org/threads/shared.html threads::shared] {{Wayback|url=http://perldoc.perl.org/threads/shared.html |date=20190715085920 }} - Perl extension for sharing data structures between threads {{软件设计模式}} [[Category:软件设计模式]] [[Category:程序架構]] [[Category:并发控制]] [[Category:并发控制]]
该页面使用的模板:
Template:Cite web
(
查看源代码
)
Template:Div col
(
查看源代码
)
Template:Div col end
(
查看源代码
)
Template:Lang-en
(
查看源代码
)
Template:NoteTA
(
查看源代码
)
Template:Reflist
(
查看源代码
)
Template:Tsl
(
查看源代码
)
Template:Wayback
(
查看源代码
)
Template:软件设计模式
(
查看源代码
)
返回
監視器 (程序同步化)
。
导航菜单
个人工具
登录
命名空间
页面
讨论
不转换
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
工具
链入页面
相关更改
页面信息