Ich habe jetzt mal angefangen kleine Videotutorials zu erstellen, in denen ich in Echtzeit einen kleinen Algorithmus oder bestimmte Programmierprinzipien entwickle und erkläre.
Dieses mal geht es um einen nebenläufige Warteschlage, oder auf Englisch „Concurrent Queue“, die nach dem „First In“-„First Out“-Prinzip arbeitet und mit Threads zurecht kommt.
Im folgenden Video erkläre ich Zeile für Zeile wie man das ganze implementiert und unter dem Video findet ihr auch den endgültigen Code.
[youtube http://www.youtube.com/watch?v=0Jyr3_PtecE]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
EnableExplicit DeclareModule ConcurrentQueue Interface Type destroy.i() countElements.i() isEmpty.i() push.i(*element) pop.i() EndInterface Declare.i new() EndDeclareModule Module ConcurrentQueue Structure Type_S *vTable List *elements() lock.i semaphore.i EndStructure Procedure.i new() Protected *this.Type_S = AllocateMemory(SizeOf(Type_S)) If (Not *this) ProcedureReturn #False EndIf InitializeStructure(*this, Type_S) With *this \vTable = ?ConcurrentQueue_vTable \semaphore = CreateSemaphore(0) If (Not \semaphore) ClearStructure(*this, Type_S) FreeMemory(*this) ProcedureReturn #False EndIf \lock = CreateMutex() If (Not \lock) FreeSemaphore(\semaphore) ClearStructure(*this, Type_S) FreeMemory(*this) ProcedureReturn #False EndIf EndWith ProcedureReturn *this EndProcedure Procedure.i destroy(*this.Type_S) With *this FreeSemaphore(\semaphore) FreeMutex(\lock) ClearStructure(*this, Type_S) EndWith FreeMemory(*this) EndProcedure Procedure.i countElements(*this.Type_S) Protected size.i With *this LockMutex(\lock) size = ListSize(\elements()) UnlockMutex(\lock) EndWith ProcedureReturn size EndProcedure Procedure.i isEmpty(*this.Type) ProcedureReturn Bool(*this\countElements() = 0) EndProcedure Procedure.i push(*this.Type_S, *element) Protected result.i = #False With *this LockMutex(\lock) LastElement(\elements()) If AddElement(\elements()) \elements() = *element SignalSemaphore(\semaphore) result = #True EndIf UnlockMutex(\lock) EndWith ProcedureReturn result EndProcedure Procedure.i pop(*this.Type_S) Protected *element With *this LockMutex(\lock) If (Not TrySemaphore(\semaphore)) UnlockMutex(\lock) WaitSemaphore(\semaphore) LockMutex(\lock) EndIf FirstElement(\elements()) *element = \elements() DeleteElement(\elements()) UnlockMutex(\lock) EndWith ProcedureReturn *element EndProcedure DataSection ConcurrentQueue_vTable: Data.i @destroy(), @countElements(), @isEmpty(), @push(), @pop() EndDataSection EndModule Define queue.ConcurrentQueue::Type = ConcurrentQueue::new() Procedure Thread(queue.ConcurrentQueue::Type) Repeat Debug "Pop: " + Str(queue\pop()) ForEver EndProcedure Define thread.i = CreateThread(@Thread(), queue) Define i.i For i = 1 To 20 Debug "Push: " + i queue\push(i) Delay(Random(30, 10)) Next Delay(5000) KillThread(thread) |
Ich würde gern den tollen Code für die ConcurrentQueue aus der Website heraus kopieren, was aber leider nicht geht, weil die Buttons am oberen Fensterrand keine Wirkung haben.
Woran liegt’s?
Hi ProgOldie,
ich hab das Problem behoben. Das lag an dem komischen Minify-Plugin, was wir genutzt haben.
Zeile 89 kann man vereinfachen.
LockMutex(\lock)
If (Not TrySemaphore(\semaphore))
UnlockMutex(\lock)
WaitSemaphore(\semaphore)
LockMutex(\lock)
EndIf
->
If (Not TrySemaphore(\semaphore))
WaitSemaphore(\semaphore)
EndIf
LockMutex(\lock)
Das muss ich mir mal genauer anschauen, ob man das wirklich vereinfachen kann. Leider habe ich dafür gerade keine Zeit, aber ich werde daran denken.