CONDWAIT
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgCondWait
- 最后更新: 2023-03-09
停止当前线程的执行,直到某个条件变为真
语法
declare sub Condwait ( byval handle as any ptr, byval mutex as any ptr )用法
Condwait ( handle, mutex )参数
handle
条件变量的句柄。
mutex
与该条件变量关联的互斥锁,在测试条件和调用 Condwait 时必须处于加锁状态。
说明
此函数停止调用它的线程,直到某个其他线程对该句柄调用 Condsignal 或 Condbroadcast。
一旦使用 Condcreate 创建了条件变量并启动了线程,其中一个或多个线程(包括执行主程序的隐式主线程)可以被设置为对该条件变量执行 Condwait;它们将被阻塞,直到某个其他线程通过 Condsignal 通知等待线程可以继续执行。Condbroadcast 可用于重新启动所有等待该条件变量的线程。程序结束时必须使用 Conddestroy 来避免操作系统资源泄漏。
调用 Condwait 时,mutex 应已处于加锁状态(使用与 Condsignal 或 Condbroadcast 相同的 mutex)。系统将原子性地解锁 mutex 并在条件变量上等待。调用线程的执行被挂起,在条件变量被发信号之前不会消耗任何 CPU 时间。当条件变量被发信号时,mutex 将重新被加锁,然后在 Condwait 调用之后的位置恢复执行,但此时互斥锁由调用者持有。调用者随后负责解锁 mutex,以完成 Condwait 子程序,使得 Condwait 调用之后的代码得以继续执行。
注意:养成使用保护措施防范虚假唤醒的好习惯是值得提倡的。
为此,将 Condwait 置于一个循环中,检查布尔断言是否确实为真(该断言由另一个线程在执行 Condsignal 或 Condbroadcast 之前设置为真),以确认线程等待结束时条件已满足:
信号发送方:
predicate = true
Condsignal(handle)等待接收方:
While predicate <> true
Condwait(handle, mutex)
Wend
predicate = false循环只有在断言为真时才能终止。
另一方面,如果在线程到达循环之前断言已经为真,Condwait 将被直接跳过(这样可以处理 Condsignal 或 Condbroadcast 在第一个线程真正等待之前就在第二个线程中过早执行的情况,否则该信号将丢失)。
详细的编码示例请参见下方示例。
示例
另请参见 Condcreate 和 Condsignal
' 这个简单的示例代码演示了多个条件变量函数的用法。
' 主程序创建三个线程。
' 其中两个线程更新一个"count"变量。
' 第三个线程等待,直到 count 变量达到指定值。
#define numThread 3
#define countThreshold 6
Dim Shared As Integer count = 0
Dim Shared As Any Ptr countMutex
Dim Shared As Any Ptr countThresholdCV
Dim As Any Ptr threadID(0 To numThread-1)
Dim Shared As Integer ok = 0
Sub threadCount (ByVal p As Any Ptr)
Print "Starting threadCount(): thread#" & p
Do
Print "threadCount(): thread#" & p & ", locking mutex"
MutexLock(countMutex)
count += 1
' 检查 count 值,当达到条件时通知等待线程。
' 注意:此操作在互斥锁加锁时执行。
If count >= countThreshold Then
If count = countThreshold Then
Print "threadCount(): thread#" & p & ", count = " & count & ", threshold reached, unlocking mutex"
ok = 1
CondSignal(countThresholdCV)
Else
Print "threadCount(): thread#" & p & ", count = " & count & ", threshold exceeded, unlocking mutex"
End If
MutexUnlock(countMutex)
Exit Do
End If
Print "threadCount(): thread#" & p & ", count = " & count & ", unlocking mutex"
MutexUnlock(countMutex)
Sleep 100, 1
Loop
End Sub
Sub threadWatch (ByVal p As Any Ptr)
Print "Starting threadWatch(): thread#" & p & ", locking mutex, waiting for conditional"
MutexLock(countMutex)
' 注意:Condwait 函数将自动以原子方式解锁互斥锁并等待。
While ok = 0
CondWait(countThresholdCV, countMutex)
Wend
Print "threadWatch(): thread#" & p & ", condition signal received"
Print "threadWatch(): thread#" & p & ", count now = " & count & ", unlocking mutex"
MutexUnlock(countMutex)
End Sub
' 创建互斥锁和条件变量
countMutex = MutexCreate
countThresholdCV = CondCreate
' 创建线程
threadID(0) = ThreadCreate(@threadWatch, Cast(Any Ptr, 1))
threadID(1) = ThreadCreate(@threadCount, Cast(Any Ptr, 2))
threadID(2) = ThreadCreate(@threadCount, Cast(Any Ptr, 3))
' 等待所有线程完成
For I As Integer = 0 To numThread-1
ThreadWait(threadID(I))
Print "Main(): Waited on thread#" & I+1 & " Done"
Next I
MutexDestroy(countMutex)
CondDestroy(countThresholdCV)平台差异
- Condwait 在 FreeBASIC 的 DOS 版本/目标中不可用,因为 DOS 内核及其所使用的扩展器均不支持多线程。
- 在 Linux 中,线程始终按创建顺序启动,这在 Win32 中无法保证。这是操作系统的问题,而非 FreeBASIC 的问题。
方言差异
- 在 -lang qb 方言中不允许使用线程
与 QB 的区别
- FreeBASIC 新增功能
另请参见
CondcreateConddestroyCondbroadcastCondsignalMutexcreateMutexlockMutexunlockThreadcreate
返回 目录