[Linux] Thread-Interface mit join
Verfasst: 15.09.2011 04:43
Hallo,
da ich gerade noch nicht schlafen konnte, habe ich noch Threads als Interface implementiert. Interessant ist daran zum Beispiel, dass es die hübsche Methode join() gibt, die ähnlich WaitThread() ist, aber den Rückgabewert eines Threads liefert. Leider funktioniert dafür aber das optionale Timeout, was es ja bei WaitThread() gibt, (noch) nicht.
Bisher konnte ich das ganze nur unter Ubuntu 10.04 x64 testen. Ich würde mich aber freuen, wenn jemand das ganze mal noch auf einem anderen Linux testet. Es könnte passieren, dass jemand die Library '/usr/lib/libglibmm-2.4.so' nicht installiert hat, aber bei mir ging es nur mit dieser einen. Leider sind auch dort nicht alle Befehle integriert, die ich gerne getestet hätte, wie z.B. g_thread_yield(). Vielleicht weiß da jemand genaueres oder kann mir sagen, welche Library ich bei 'ImportC' in Zeile 42 des Includes wählen muss, damit es auch wirklich bei jedem out-of-the-box funktioniert.
Bei Gelegenheit oder durch Mithilfe anderer programmierfreudiger Boardnutzer wäre als nächstes angedacht das Interface auch für Windows anzupassen, damit man am Ende eine Include hat, die alles kann. Als nächstes würden dann Mutexe, Conditions und evtl. das in glib integrierte Reader-Writer-Lock als weitere Includes anstehen.
Weitere Informationen zur 'glib' finden sich hier: glib-Threads
Es folgen nun wie immer zuerst die Include und dann ein Beispiel.
Thread.pbi
Thread_Example.pbi
da ich gerade noch nicht schlafen konnte, habe ich noch Threads als Interface implementiert. Interessant ist daran zum Beispiel, dass es die hübsche Methode join() gibt, die ähnlich WaitThread() ist, aber den Rückgabewert eines Threads liefert. Leider funktioniert dafür aber das optionale Timeout, was es ja bei WaitThread() gibt, (noch) nicht.
Bisher konnte ich das ganze nur unter Ubuntu 10.04 x64 testen. Ich würde mich aber freuen, wenn jemand das ganze mal noch auf einem anderen Linux testet. Es könnte passieren, dass jemand die Library '/usr/lib/libglibmm-2.4.so' nicht installiert hat, aber bei mir ging es nur mit dieser einen. Leider sind auch dort nicht alle Befehle integriert, die ich gerne getestet hätte, wie z.B. g_thread_yield(). Vielleicht weiß da jemand genaueres oder kann mir sagen, welche Library ich bei 'ImportC' in Zeile 42 des Includes wählen muss, damit es auch wirklich bei jedem out-of-the-box funktioniert.
Bei Gelegenheit oder durch Mithilfe anderer programmierfreudiger Boardnutzer wäre als nächstes angedacht das Interface auch für Windows anzupassen, damit man am Ende eine Include hat, die alles kann. Als nächstes würden dann Mutexe, Conditions und evtl. das in glib integrierte Reader-Writer-Lock als weitere Includes anstehen.
Weitere Informationen zur 'glib' finden sich hier: glib-Threads
Es folgen nun wie immer zuerst die Include und dann ein Beispiel.
Thread.pbi
Code: Alles auswählen
EnableExplicit
Interface Thread
free.i()
currentThread.i()
getName.s()
getPriority.i()
isAlive.i()
join.i()
run.i()
setName.i(name.s)
setPriority.i(newPriority.i)
getErrorMessage.s()
; It is Not guaranteed that threads With different priorities really behave
; accordingly. On some systems (e.g. Linux) there are no thread priorities.
; On other systems (e.g. Solaris) there doesn't seem to be different
; scheduling For different priorities. All in all try To avoid being
; dependent on priorities.
start.i()
EndInterface
Prototype.i Thread_Prototype(*threadData)
Structure Thread_S
*vTable
*hThread.GThread
*function.Thread_Prototype
*pError.Integer
name.s
priority.i
interrupted.i
*threadData
EndStructure
Enumeration
#G_THREAD_PRIORITY_LOW
#G_THREAD_PRIORITY_NORMAL
#G_THREAD_PRIORITY_HIGH
#G_THREAD_PRIORITY_URGENT
EndEnumeration
ImportC "/usr/lib/libglibmm-2.4.so"
g_thread_init(*vTable)
g_thread_get_initialized.i()
g_thread_create_full.i(*func, *threadData, stack_size.i, joinable.i, bound.i, priority.i, *pError)
g_thread_self.i()
g_thread_join.i(*thread.GTHREAD)
;g_thread_yield()
g_thread_set_priority(*thread.GTHREAD, priority.i)
g_thread_exit(*returnValue)
EndImport
Procedure.s Thread_getErrorMessage(*this.Thread_S)
Protected *error.GERROR, msg.s
*error = *this\pError\i
msg = "domain: " + Str(*error\domain) + #LF$
msg + "code: " + Str(*Error\code) + #LF$
msg + "message: " + PeekS(*error, #PB_Ascii)
ProcedureReturn msg
EndProcedure
Procedure.i newThread(*function.Thread_Prototype, *threadData = #Null, name.s = "")
Protected *this.Thread_S
*this = AllocateMemory(SizeOf(Thread_S))
If (Not *this)
ProcedureReturn
EndIf
InitializeStructure(*this, Thread_S)
If (Not g_thread_get_initialized())
g_thread_init(#Null)
EndIf
With *this
\vTable = ?Thread_vTable
\threadData = *threadData
\function = *function
\pError = AllocateMemory(SizeOf(Integer))
\hThread = 0;
\name = name
\priority = #G_THREAD_PRIORITY_NORMAL
\interrupted = #False
EndWith
ProcedureReturn *this
EndProcedure
Procedure.i Thread_currentThread(*this.Thread_S = 0)
Protected *gThread.GTHREAD
If (Not *this)
*gThread = g_thread_self()
*this = *gThread\data
EndIf
ProcedureReturn *this
EndProcedure
Procedure.i Thread_join(*this.Thread_S)
Protected *returnValue
With *this
If (Not \hThread)
ProcedureReturn #False
EndIf
*returnValue = g_thread_join(\hThread)
EndWith
ProcedureReturn *returnValue
EndProcedure
Procedure.i Thread_setPriority(*this.Thread_S, priority.i)
With *this
If (Not \hThread)
ProcedureReturn #False
EndIf
\priority = priority
g_thread_set_priority(\hThread, \priority)
EndWith
ProcedureReturn #True
EndProcedure
Procedure.s Thread_getName(*this.Thread_S = 0)
If (Not *this)
*this = Thread_currentThread()
EndIf
If (*this)
ProcedureReturn *this\name
EndIf
ProcedureReturn "[NO THREAD]"
EndProcedure
Procedure.i Thread_setName(*this.Thread_S, name.s)
*this\name = name
ProcedureReturn #True
EndProcedure
Procedure.i Thread_run(*this.Thread_S)
Protected *returnValue
With *this
*returnValue = \function(\threadData)
\hThread = 0
EndWith
ProcedureReturn *returnValue
EndProcedure
Procedure.i Thread_start(*this.Thread_S)
With *this
\hThread = g_thread_create_full(@Thread_run(), *this, SizeOf(Integer), #True, #False, \priority, \pError)
If (\hThread = #Null)
ProcedureReturn #False
EndIf
EndWith
EndProcedure
Procedure.i Thread_isAlive(*this.Thread_S)
If (*this\hThread)
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i Thread_getPriority(*this.Thread_S = 0)
If (Not *this)
*this = Thread_currentThread()
EndIf
If (*this)
ProcedureReturn *this\priority
EndIf
EndProcedure
Procedure.i Thread_free(*this.Thread_S)
Protected *returnValue
*returnValue = Thread_join(*this)
FreeMemory(*this\pError)
ClearStructure(*this, Thread_S)
ProcedureReturn *returnValue
EndProcedure
DataSection
Thread_vTable:
Data.i @Thread_free() ;done
Data.i @Thread_currentThread() ;done
Data.i @Thread_getName() ;done
Data.i @Thread_getPriority() ;done
Data.i @Thread_isAlive() ;done
Data.i @Thread_join() ;done
Data.i @Thread_run() ;done
Data.i @Thread_setName() ;done
Data.i @Thread_setPriority() ;done
Data.i @Thread_getErrorMessage();done
Data.i @Thread_start() ;done
EndDataSection
Code: Alles auswählen
XIncludeFile "Thread.pbi"
Procedure.i testThread(*threadData)
Delay(200)
Debug "*threadData = " + Str(*threadData)
Debug "My name is '" + Thread_getName() + "' and my priority is '" + Str(Thread_getPriority()) + "'"
Delay(1000)
Debug "Thread ends"
ProcedureReturn 456
EndProcedure
Define thread.Thread = newThread(@testThread(), 123, "Thread 1")
Debug "Start thread '" + thread\getName() + "'"
thread\start()
Debug "isAlive() = " + Str(thread\isAlive())
Delay(100)
Debug "Thread should still run"
Debug "isAlive() = " + Str(thread\isAlive())
Debug "Return value from thread: " + Str(thread\join())
Debug "isAlive() = " + Str(thread\isAlive())
Debug "End of the program"
Debug "Start thread again (no free())"
thread\start()
Debug "Return value from free(): " + Str(thread\free())