CONDCREATE
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgCondCreate
- 最后更新: 2024-03-13
创建用于线程同步的条件变量
语法
declare function Condcreate ( ) as any ptr用法
result = Condcreate返回值
新创建的条件变量的句柄,失败时返回空指针(0)。
说明
一旦使用 Condcreate 创建了条件变量并启动了线程,其中一个或多个线程(包括执行主程序的隐式主线程)可以被设置为对该条件变量执行 Condwait,它们将被阻塞,直到某个其他线程通过 Condsignal 通知等待线程可以继续执行。Condbroadcast 可用于重新启动所有等待该条件变量的线程。程序结束时必须使用 Conddestroy 来避免操作系统资源泄漏。
示例
另请参见 Condwait、Condsignal 和 Condbroadcast
vb
''
'' 让新创建的线程等待,直到所有线程都准备好,然后同时启动它们
''
Dim Shared hcondstart As Any Ptr
Dim Shared hmutexstart As Any Ptr
Dim Shared start As Integer = 0
Dim Shared threadcount As Integer
Dim Shared hmutexready As Any Ptr
Dim Shared hcondready As Any Ptr
Sub mythread(ByVal id_ptr As Any Ptr)
Dim id As Integer = Cast(Integer, id_ptr)
'' 通知该线程已准备好
MutexLock hmutexready
threadcount += 1
Print "Thread #" & id & " is waiting..."
CondSignal hcondready
MutexUnlock hmutexready
'' 等待启动信号
MutexLock hmutexstart
Do While start = 0
CondWait hcondstart, hmutexstart
Loop
'' 此时该线程持有 hmutexstart 的锁
MutexUnlock hmutexstart
'' 输出该线程的编号
For i As Integer = 1 To 40
Print id;
Next i
End Sub
Dim threads(1 To 9) As Any Ptr
hcondstart = CondCreate()
hmutexstart = MutexCreate()
hcondready = CondCreate()
hmutexready = MutexCreate()
threadcount = 0
MutexLock(hmutexready)
For i As Integer = 1 To 9
threads(i) = ThreadCreate(@mythread, Cast(Any Ptr, i))
If threads(i) = 0 Then
Print "unable to create thread"
End If
Next i
Print "Waiting until all threads are ready..."
Do Until threadcount = 9
CondWait(hcondready, hmutexready)
Loop
MutexUnlock(hmutexready)
Print
Print "Go!"
MutexLock hmutexstart
start = 1
CondBroadcast hcondstart
MutexUnlock hmutexstart
'' 等待所有线程完成
For i As Integer = 1 To 9
If threads(i) <> 0 Then
ThreadWait threads(i)
End If
Next i
MutexDestroy hmutexready
CondDestroy hcondready
MutexDestroy hmutexstart
CondDestroy hcondstartvb
'使用 Mutex 和 CondVar 实现两个线程间互斥与同步的可视化示例:
'"用户定义线程"计算圆上各点的坐标,
'"主线程"绘制这些点。
'
'互斥与同步原理
' 线程#A XOR + `<==>` 线程#B
'..... .....
'MutexLock(mut) MutexLock(mut)
' 带互斥的操作 带互斥的操作
' While bool#1 <> true <------------------------ bool#1 = true
' CondWait(cond#1, mut) <--------------------- CondSignal(cond#1)
' Wend <-----------------------------------. 带互斥的操作
' bool#1 = false .---------- | --> While bool#2 <> true
' 带互斥的操作 | .------ | ----> CondWait(cond#2, mut)
' bool#2 = true ---------------' | .-- | --> Wend
' CondSignal(cond#2) --------------' | | bool#2 = false
' 带互斥的操作 | | 带互斥的操作
'MutexUnlock(mut) ----------------------' '-- MutexUnlock(mut)
'..... .....
'
'行为:
'- 无需预先计算第一个点。
'- 每个计算出的点只被绘制一次。
'
'如果注释掉包含"MutexLock"和"MutexUnlock"的行,
'"CondWait"和"CondSignal"以及".ready"
'(在"用户定义线程"或/和"主线程"中),
'坐标计算与点的绘制之间将不再保持互斥和同步,
'许多点将不会被绘制在圆上(因为坐标数据不一致)。
'-----------------------------------------------------------------------------------------------------
Type ThreadUDT '通用用户线程 UDT
Dim handle As Any Ptr '用户线程的 Any Ptr 句柄
Dim sync As Any Ptr '互斥锁的 Any Ptr 句柄
Dim cond1 As Any Ptr '条件变量1的 Any Ptr 句柄
Dim cond2 As Any Ptr '条件变量2的 Any Ptr 句柄
Dim ready1 As Byte '坐标 ready1 的布尔值
Dim ready2 As Byte '坐标 ready2 的布尔值
Dim quit As Byte '结束用户线程的布尔值
Declare Static Sub Thread (ByVal As Any Ptr) '通用用户线程过程
Dim procedure As Sub (ByVal As Any Ptr) '由用户线程执行的过程(Any Ptr)
Dim p As Any Ptr '传递给用户线程执行过程的 Any Ptr
Const false As Byte = 0 '常量 "false"
Const true As Byte = Not false '常量 "true"
End Type
Static Sub ThreadUDT.Thread (ByVal param As Any Ptr) '通用用户线程过程
Dim tp As ThreadUDT Ptr = param '转换为通用用户线程 UDT
Do
Static As Integer I
MutexLock(tp->sync) '用户线程的互斥锁(加锁)
tp->procedure(tp->p) '执行用户线程的过程(Any Ptr)
I += 1
Locate 30, 38
Print I;
tp->ready1 = true '设置 ready1
CondSignal(tp->cond1) '向主线程发送信号1
While tp->ready2 <> true '防止虚假唤醒的循环
CondWait(tp->cond2, tp->sync) '等待主线程的信号2
Wend
tp->ready2 = false
If tp->quit = tp->true Then '检测是否结束用户线程
MutexUnlock(tp->sync) '用户线程的互斥锁(解锁)
Exit Do
End If
MutexUnlock(tp->sync) '用户线程的互斥锁(解锁)
Sleep 5, 1
Loop
End Sub
'-----------------------------------------------------------------------------------------------------
Type Point2D
Dim x As Integer
Dim y As Integer
End Type
Const x0 As Integer = 640 / 2
Const y0 As Integer = 480 / 2
Const r0 As Integer = 200
Const pi As Single = 4 * Atn(1)
Sub PointOnCircle (ByVal p As Any Ptr)
Dim pp As Point2D Ptr = p
Dim teta As Single = 2 * pi * Rnd
pp->x = x0 + r0 * Cos(teta)
Sleep 5, 1 '增加出现不相关数据的可能性
pp->y = y0 + r0 * Sin(teta)
End Sub
Screen 12
Locate 30, 2
Print "`<any_key>` : exit";
Locate 30, 27
Print "calculated:";
Locate 30, 54
Print "plotted:";
Dim Pptr As Point2D Ptr = New Point2D
Dim Tptr As ThreadUDT Ptr = New ThreadUDT
Tptr->sync = MutexCreate
Tptr->cond1 = CondCreate
Tptr->cond2 = CondCreate
Tptr->procedure = @PointOnCircle
Tptr->p = Pptr
Tptr->handle = ThreadCreate(@ThreadUDT.Thread, Tptr)
Do
Static As Integer I
MutexLock(Tptr->sync) '主线程的互斥锁(加锁)
While Tptr->ready1 <> Tptr->true '防止虚假唤醒的循环
CondWait(Tptr->cond1, Tptr->sync) '等待用户线程的信号1
Wend
Tptr->ready1 = Tptr->false
PSet (Pptr->x, Pptr->y) '绘制一个点
I += 1
Locate 30, 62
Print I;
Tptr->ready2 = Tptr->true '设置 ready2
CondSignal(Tptr->cond2) '向用户线程发送信号2
If Inkey <> "" Then
Tptr->quit = Tptr->true '设置退出标志
MutexUnlock(Tptr->sync) '主线程的互斥锁(解锁)
Exit Do
End If
MutexUnlock(Tptr->sync) '主线程的互斥锁(解锁)
Sleep 5, 1
Loop
ThreadWait(Tptr->handle)
MutexDestroy(Tptr->sync)
CondDestroy(Tptr->cond1)
CondDestroy(Tptr->cond2)
Delete Tptr
Delete Pptr
Sleep另请参见类似的 Mutexcreate 示例
平台差异
- Condcreate 在 FreeBASIC 的 DOS 版本/目标中不可用,因为 DOS 内核及其所使用的扩展器均不支持多线程。
方言差异
- 在 -lang qb 方言中不允许使用线程
与 QB 的区别
- FreeBASIC 新增功能
另请参见
返回 目录