Skip to content

CONDWAIT


停止当前线程的执行,直到某个条件变为真

语法

declare sub Condwait ( byval handle as any ptr, byval mutex as any ptr )

用法

Condwait ( handle, mutex )

参数

handle

条件变量的句柄。

mutex

与该条件变量关联的互斥锁,在测试条件和调用 Condwait 时必须处于加锁状态。

说明

此函数停止调用它的线程,直到某个其他线程对该句柄调用 CondsignalCondbroadcast

一旦使用 Condcreate 创建了条件变量并启动了线程,其中一个或多个线程(包括执行主程序的隐式主线程)可以被设置为对该条件变量执行 Condwait;它们将被阻塞,直到某个其他线程通过 Condsignal 通知等待线程可以继续执行。Condbroadcast 可用于重新启动所有等待该条件变量的线程。程序结束时必须使用 Conddestroy 来避免操作系统资源泄漏。

调用 Condwait 时,mutex 应已处于加锁状态(使用与 CondsignalCondbroadcast 相同的 mutex)。系统将原子性地解锁 mutex 并在条件变量上等待。调用线程的执行被挂起,在条件变量被发信号之前不会消耗任何 CPU 时间。当条件变量被发信号时,mutex 将重新被加锁,然后在 Condwait 调用之后的位置恢复执行,但此时互斥锁由调用者持有。调用者随后负责解锁 mutex,以完成 Condwait 子程序,使得 Condwait 调用之后的代码得以继续执行。

注意:养成使用保护措施防范虚假唤醒的好习惯是值得提倡的。

为此,将 Condwait 置于一个循环中,检查布尔断言是否确实为真(该断言由另一个线程在执行 CondsignalCondbroadcast 之前设置为真),以确认线程等待结束时条件已满足:

信号发送方:

predicate = true
Condsignal(handle)

等待接收方:

While predicate <> true

Condwait(handle, mutex)

Wend
predicate = false

循环只有在断言为真时才能终止。

另一方面,如果在线程到达循环之前断言已经为真,Condwait 将被直接跳过(这样可以处理 CondsignalCondbroadcast 在第一个线程真正等待之前就在第二个线程中过早执行的情况,否则该信号将丢失)。

详细的编码示例请参见下方示例。

示例

另请参见 CondcreateCondsignal

vb
' 这个简单的示例代码演示了多个条件变量函数的用法。
' 主程序创建三个线程。
' 其中两个线程更新一个"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 新增功能

另请参见

  • Condcreate
  • Conddestroy
  • Condbroadcast
  • Condsignal
  • Mutexcreate
  • Mutexlock
  • Mutexunlock
  • Threadcreate

返回 目录

基于 FreeBASIC 官方文档翻译 如有侵权请联系我们删除
FreeBASIC 是开源项目,与微软公司无隶属关系