|
| 1 | +'' examples/manual/threads/condcreate2.bas |
| 2 | +'' |
| 3 | +'' NOTICE: This file is part of the FreeBASIC Compiler package and can't |
| 4 | +'' be included in other distributions without authorization. |
| 5 | +'' |
| 6 | +'' See Also: http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgCondCreate |
| 7 | +'' -------- |
| 8 | + |
| 9 | +'Visual example of mutual exclusion + mutual synchronization between 2 threads |
| 10 | +'by using Mutex and CondVar: |
| 11 | +'the "user-defined thread" computes the points coordinates on a circle, |
| 12 | +'and the "main thread" plots the points. |
| 13 | +' |
| 14 | +'Principle of mutual exclusion + mutual synchronisation |
| 15 | +' Thread#A XOR + <==> Thread#B |
| 16 | +'..... ..... |
| 17 | +'MutexLock(mut) MutexLock(mut) |
| 18 | +' While Thread#A_signal <> false While Thread#A_signal <> true |
| 19 | +' CondWait(cond, mut) CondWait(cond, mut) |
| 20 | +' Wend Wend |
| 21 | +' Do_something#A_with_exclusion Do_something#B_with_exclusion |
| 22 | +' Thread#A_signal = true Thread#A_signal = false |
| 23 | +' CondSignal(cond) CondSignal(cond) |
| 24 | +'MutexUnlock(mut) MutexUnlock(mut) |
| 25 | +'..... ..... |
| 26 | +' |
| 27 | +'Behavior: |
| 28 | +'- Unnecessary to pre-calculate the first point. |
| 29 | +'- Each calculated point is plotted one time only. |
| 30 | +' |
| 31 | +'If you comment out the lines containing "MutexLock" and "MutexUnlock", |
| 32 | +'"CondWait" and "CondSignal", ".ready" |
| 33 | +'(inside "user-defined thread" or/and "main thread"), |
| 34 | +'there will be no longer mutual exclusion nor mutual synchronization |
| 35 | +'between computation of coordinates and plotting of points, |
| 36 | +'and many points will not be plotted on circle (due to non coherent coordinates). |
| 37 | + |
| 38 | +'----------------------------------------------------------------------------------------------------- |
| 39 | + |
| 40 | +Type ThreadUDT 'Generic user thread UDT |
| 41 | + Dim handle As Any Ptr 'Any Ptr handle to user thread |
| 42 | + Dim sync As Any Ptr 'Any Ptr handle to mutex |
| 43 | + Dim cond As Any Ptr 'Any Ptr handle to conditional |
| 44 | + Dim ready As Byte 'Boolean to coordinates ready |
| 45 | + Dim quit As Byte 'Boolean to end user thread |
| 46 | + Declare Static Sub Thread (ByVal As Any Ptr) 'Generic user thread procedure |
| 47 | + Dim procedure As Sub (ByVal As Any Ptr) 'Procedure(Any Ptr) to be executed by user thread |
| 48 | + Dim p As Any Ptr 'Any Ptr to pass to procedure executed by user thread |
| 49 | + Const false As Byte = 0 'Constante "false" |
| 50 | + Const true As Byte = Not false 'Constante "true" |
| 51 | +End Type |
| 52 | + |
| 53 | +Static Sub ThreadUDT.Thread (ByVal param As Any Ptr) 'Generic user thread procedure |
| 54 | + Dim tp As ThreadUDT Ptr = param 'Casting to generic user thread UDT |
| 55 | + Do |
| 56 | + Static As Integer I |
| 57 | + MutexLock(tp->sync) 'Mutex (Lock) for user thread |
| 58 | + While tp->Ready <> false 'Process loop against spurious wakeups |
| 59 | + CondWait(tp->cond, tp->sync) 'CondWait to receive signal from main-thread |
| 60 | + Wend |
| 61 | + tp->procedure(tp->p) 'Procedure(Any Ptr) to be executed by user thread |
| 62 | + I += 1 |
| 63 | + Locate 30, 38 |
| 64 | + Print I; |
| 65 | + tp->Ready = true 'Set Ready |
| 66 | + CondSignal(tp->cond) 'CondSignal to send signal to main thread |
| 67 | + MutexUnlock(tp->sync) 'Mutex (Unlock) for user thread |
| 68 | + Sleep 5 |
| 69 | + Loop Until tp->quit = tp->true 'Test for ending user thread |
| 70 | +End Sub |
| 71 | + |
| 72 | +'----------------------------------------------------------------------------------------------------- |
| 73 | + |
| 74 | +Type Point2D |
| 75 | + Dim x As Integer |
| 76 | + Dim y As Integer |
| 77 | +End Type |
| 78 | + |
| 79 | +Const x0 As Integer = 640 / 2 |
| 80 | +Const y0 As Integer = 480 / 2 |
| 81 | +Const r0 As Integer = 200 |
| 82 | +Const pi As Single = 4 * Atn(1) |
| 83 | + |
| 84 | +Sub PointOnCircle (ByVal p As Any Ptr) |
| 85 | + Dim pp As Point2D Ptr = p |
| 86 | + Dim teta As Single = 2 * pi * Rnd |
| 87 | + pp->x = x0 + r0 * Cos(teta) |
| 88 | + Sleep 5 'To increase possibility of uncorrelated data occurrence |
| 89 | + pp->y = y0 + r0 * Sin(teta) |
| 90 | +End Sub |
| 91 | + |
| 92 | + |
| 93 | +Screen 12 |
| 94 | +Locate 30, 2 |
| 95 | +Print "<any_key> : exit"; |
| 96 | +Locate 30, 27 |
| 97 | +Print "calculated:"; |
| 98 | +Locate 30, 54 |
| 99 | +Print "plotted:"; |
| 100 | + |
| 101 | +Dim Pptr As Point2D Ptr = New Point2D |
| 102 | + |
| 103 | +Dim Tptr As ThreadUDT Ptr = New ThreadUDT |
| 104 | +Tptr->sync = MutexCreate |
| 105 | +Tptr->cond = CondCreate |
| 106 | +Tptr->procedure = @PointOnCircle |
| 107 | +Tptr->p = Pptr |
| 108 | +Tptr->handle = ThreadCreate(@ThreadUDT.Thread, Tptr) |
| 109 | + |
| 110 | +Do |
| 111 | + Static As Integer I |
| 112 | + Sleep 5 |
| 113 | + MutexLock(Tptr->sync) 'Mutex (Lock) for main thread |
| 114 | + While Tptr->ready <> Tptr->true 'Process loop against spurious wakeups |
| 115 | + CondWait(Tptr->cond, Tptr->sync) 'CondWait to receive signal from user-thread |
| 116 | + Wend |
| 117 | + PSet (Pptr->x, Pptr->y) 'Plotting one point |
| 118 | + I += 1 |
| 119 | + Locate 30, 62 |
| 120 | + Print I; |
| 121 | + Tptr->Ready = Tptr->false 'Reset Ready |
| 122 | + CondSignal(Tptr->cond) 'CondSignal to send signal to user thread |
| 123 | + MutexUnlock(Tptr->sync) 'Mutex (Unlock) for main thread |
| 124 | +Loop Until Inkey <> "" |
| 125 | + |
| 126 | +Tptr->quit = Tptr->true |
| 127 | +ThreadWait(Tptr->handle) |
| 128 | +MutexDestroy(Tptr->sync) |
| 129 | +CondDestroy(Tptr->cond) |
| 130 | +Delete Tptr |
| 131 | +Delete Pptr |
| 132 | + |
| 133 | +Sleep |
0 commit comments