threads.bmx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. SuperStrict
  2. Rem
  3. bbdoc: System/Threads
  4. End Rem
  5. Module BRL.Threads
  6. ModuleInfo "Version: 1.03"
  7. ModuleInfo "License: zlib/libpng"
  8. ModuleInfo "Copyright: Blitz Research Ltd"
  9. ModuleInfo "History: 1.03"
  10. ModuleInfo "History: Added TFuture type."
  11. ModuleInfo "History: 1.02"
  12. ModuleInfo "History: Changed to use macOS dispatch semphores."
  13. ModuleInfo "History: 1.01"
  14. ModuleInfo "History: Use Byte Ptr instead of Int handles."
  15. ModuleInfo "History: 1.00"
  16. ModuleInfo "History: Initial release."
  17. ?Threaded And macos
  18. Import "threads_mac.m"
  19. ?Threaded
  20. Import "threads.c"
  21. Private
  22. Extern
  23. Function bbThreadAllocData:Int()
  24. Function bbThreadSetData( index:Int,data:Object )
  25. Function bbThreadGetData:Object( index:Int )
  26. Function bbAtomicCAS:Int( target:Int Ptr,old_value:Int,new_value:Int )="int bbAtomicCAS( int *,int ,int )!"
  27. Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
  28. Function threads_CreateThread:Byte Ptr( entry:Object( data:Object ),data:Object )
  29. Function threads_DetachThread( thread:Byte Ptr )
  30. Function threads_WaitThread:Object( thread:Byte Ptr )
  31. Function threads_CreateMutex:Byte Ptr()
  32. Function threads_CloseMutex( mutex:Byte Ptr )
  33. Function threads_LockMutex( mutex:Byte Ptr )
  34. Function threads_TryLockMutex:Int( mutex:Byte Ptr )
  35. Function threads_UnlockMutex( mutex:Byte Ptr )
  36. Function threads_CreateSemaphore:Byte Ptr( count:Int )
  37. Function threads_CloseSemaphore( sema:Byte Ptr )
  38. Function threads_WaitSemaphore( sema:Byte Ptr )
  39. Function threads_PostSemaphore( sema:Byte Ptr )
  40. Function threads_TimedWaitSemaphore:Int( sema:Byte Ptr, millis:Int )
  41. Function threads_CreateCond:Byte Ptr()
  42. Function threads_WaitCond( cond:Byte Ptr,mutex:Byte Ptr )
  43. Function threads_SignalCond( cond:Byte Ptr )
  44. Function threads_BroadcastCond( cond:Byte Ptr )
  45. Function threads_CloseCond( cond:Byte Ptr )
  46. Function threads_TimedWaitCond:Int( cond:Byte Ptr,mutex:Byte Ptr, millis:Int )
  47. End Extern
  48. Global _mainThread:TThread=New TThread
  49. Global _curThread:TThreadData=TThreadData.Create()
  50. _curThread.SetValue _mainThread
  51. Public
  52. Rem
  53. bbdoc: Thread type
  54. End Rem
  55. Type TThread
  56. Rem
  57. bbdoc: Detach this thread
  58. End Rem
  59. Method Detach()
  60. If Not _handle Return 'don't Assert, as Detach is a form of Close() which always works...
  61. threads_DetachThread _handle
  62. _handle=0
  63. End Method
  64. Rem
  65. bbdoc: Wait for this thread to finish
  66. returns: The object returned by the thread.
  67. End Rem
  68. Method Wait:Object()
  69. If Not _handle Return _result 'don't Assert, as Wait is a form of Close() which always works...
  70. threads_WaitThread _handle
  71. _handle=0
  72. Return _result
  73. End Method
  74. Rem
  75. bbdoc: Check if this thread is running
  76. End Rem
  77. Method Running:Int()
  78. Return _running
  79. End Method
  80. Rem
  81. bbdoc: Create a new thread
  82. End Rem
  83. Function Create:TThread( entry:Object( data:Object),data:Object )
  84. Local thread:TThread=New TThread
  85. thread._entry=entry
  86. thread._data=data
  87. thread._running=True
  88. thread._handle=threads_CreateThread( _EntryStub,thread )
  89. Return thread
  90. End Function
  91. Rem
  92. bbdoc: Get main thread
  93. returns: A thread object representing the main application thread.
  94. End Rem
  95. Function Main:TThread()
  96. Return _mainThread
  97. End Function
  98. Rem
  99. bbdoc: Get current thread
  100. returns: A thread object representing the current thread.
  101. End Rem
  102. Function Current:TThread()
  103. Return TThread( _curThread.GetValue() )
  104. End Function
  105. Function _EntryStub:Object( data:Object )
  106. Local thread:TThread=TThread( data )
  107. _curThread.SetValue thread
  108. thread._result=thread._entry( thread._data )
  109. thread._running=False
  110. End Function
  111. Method Delete()
  112. If _handle threads_DetachThread _handle
  113. End Method
  114. Field _running:Int
  115. Field _handle:Byte Ptr
  116. Field _result:Object
  117. Field _entry:Object( data:Object )
  118. Field _data:Object
  119. End Type
  120. Rem
  121. bbdoc: ThreadData type
  122. End Rem
  123. Type TThreadData
  124. Rem
  125. bbdoc: Set thread data value
  126. End Rem
  127. Method SetValue( value:Object )
  128. bbThreadSetData _handle,value
  129. End Method
  130. Rem
  131. bbdoc: Get thread data value
  132. End Rem
  133. Method GetValue:Object()
  134. Return bbThreadGetData( _handle )
  135. End Method
  136. Rem
  137. bbdoc: Create thread data
  138. End Rem
  139. Function Create:TThreadData()
  140. Local handle:Int=bbThreadAllocData()
  141. If Not handle Return Null
  142. Local data:TThreadData=New TThreadData
  143. data._handle=handle
  144. Return data
  145. End Function
  146. Field _handle:Int
  147. End Type
  148. Rem
  149. bbdoc: Mutex type
  150. End Rem
  151. Type TMutex
  152. Rem
  153. bbdoc: Close the mutex
  154. End Rem
  155. Method Close()
  156. If Not _handle Return
  157. threads_CloseMutex _handle
  158. _handle=0
  159. End Method
  160. Rem
  161. bbdoc: Lock the mutex
  162. End Rem
  163. Method Lock()
  164. Assert _handle
  165. threads_LockMutex _handle
  166. End Method
  167. Rem
  168. bbdoc: Try to lock the mutex
  169. returns: #True if mutex was successfully locked; #False if mutex was already locked by another thread.
  170. End Rem
  171. Method TryLock:Int()
  172. Assert _handle
  173. Return threads_TryLockMutex( _handle )
  174. End Method
  175. Rem
  176. bbdoc: Unlock the mutex
  177. End Rem
  178. Method Unlock()
  179. Assert _handle
  180. threads_UnlockMutex _handle
  181. End Method
  182. Rem
  183. bbdoc: Create a new mutex
  184. End Rem
  185. Function Create:TMutex()
  186. Local handle:Byte Ptr=threads_CreateMutex()
  187. If Not handle Return Null
  188. Local mutex:TMutex=New TMutex
  189. mutex._handle=handle
  190. Return mutex
  191. End Function
  192. Method Delete()
  193. If _handle threads_CloseMutex _handle
  194. End Method
  195. Field _handle:Byte Ptr
  196. End Type
  197. Rem
  198. bbdoc: Semaphore type
  199. End Rem
  200. Type TSemaphore
  201. Rem
  202. bbdoc: Close the semaphore
  203. End Rem
  204. Method Close()
  205. If Not _handle Return
  206. threads_CloseSemaphore _handle
  207. _handle=0
  208. End Method
  209. Rem
  210. bbdoc: Wait for the semaphore
  211. End Rem
  212. Method Wait()
  213. Assert _handle
  214. threads_WaitSemaphore _handle
  215. End Method
  216. Rem
  217. bbdoc: Wait for the semaphore
  218. End Rem
  219. Method TimedWait:Int(millis:Int)
  220. Assert _handle
  221. Return threads_TimedWaitSemaphore(_handle, millis)
  222. End Method
  223. Rem
  224. bbdoc: Post the semaphore
  225. End Rem
  226. Method Post()
  227. Assert _handle
  228. threads_PostSemaphore _handle
  229. End Method
  230. Rem
  231. bbdoc: Create a new semaphore
  232. End Rem
  233. Function Create:TSemaphore( count:Int )
  234. Local handle:Byte Ptr=threads_CreateSemaphore( count )
  235. If Not handle Return Null
  236. Local semaphore:TSemaphore=New TSemaphore
  237. semaphore._handle=handle
  238. Return semaphore
  239. End Function
  240. Method Delete()
  241. If _handle threads_CloseSemaphore _handle
  242. End Method
  243. Field _handle:Byte Ptr
  244. End Type
  245. Rem
  246. bbdoc: CondVar type
  247. End Rem
  248. Type TCondVar
  249. Rem
  250. bbdoc: Close the condvar
  251. End Rem
  252. Method Close()
  253. If Not _handle Return
  254. threads_CloseCond _handle
  255. _handle=0
  256. End Method
  257. Rem
  258. bbdoc: Wait for the condvar
  259. End Rem
  260. Method Wait( mutex:TMutex )
  261. Assert _handle
  262. threads_WaitCond _handle,mutex._handle
  263. End Method
  264. Rem
  265. bbdoc: Wait for the condvar
  266. End Rem
  267. Method TimedWait:Int( mutex:TMutex, millis:Int )
  268. Assert _handle
  269. Return threads_TimedWaitCond(_handle,mutex._handle, millis)
  270. End Method
  271. Rem
  272. bbdoc: Signal the condvar
  273. End Rem
  274. Method Signal()
  275. Assert _handle
  276. threads_SignalCond _handle
  277. End Method
  278. Rem
  279. bbdoc: Broadcast the condvar
  280. End Rem
  281. Method Broadcast()
  282. Assert _handle
  283. threads_BroadcastCond _handle
  284. End Method
  285. Rem
  286. bbdoc: Create a new condvar
  287. End Rem
  288. Function Create:TCondVar()
  289. Local handle:Byte Ptr=threads_CreateCond()
  290. If Not handle Return Null
  291. Local condvar:TCondVar=New TCondVar
  292. condvar._handle=handle
  293. Return condvar
  294. End Function
  295. Method Delete()
  296. If _handle threads_CloseCond _handle
  297. End Method
  298. Field _handle:Byte Ptr
  299. End Type
  300. Rem
  301. bbdoc: A generic type for asynchronous result handling, allowing threads to wait for and retrieve results safely.
  302. about: It provides a mechanism for one thread to produce a result that another thread can wait for and retrieve
  303. at a later time. This is particularly useful for tasks that are executed in parallel, where the completion
  304. time may vary, and the consumer needs to wait for the result before proceeding.
  305. End Rem
  306. Type TFuture<V>
  307. Private
  308. Field value:V
  309. Field ready:Int
  310. Field condvar:TCondVar=CreateCondVar()
  311. Field mutex:TMutex=CreateMutex()
  312. Public
  313. Rem
  314. bbdoc: Waits for the result to become available and then returns it.
  315. about: This method blocks the calling thread until result is available.
  316. End Rem
  317. Method GetResult:V()
  318. mutex.Lock()
  319. While Not ready
  320. condvar.Wait( mutex )
  321. Wend
  322. Local result:V = value
  323. mutex.Unlock()
  324. Return result
  325. End Method
  326. Rem
  327. bbdoc: Sets the result of the asynchronous operation and signals any waiting threads.
  328. End Rem
  329. Method SetResult( value:V )
  330. mutex.Lock()
  331. Self.value=value
  332. Self.ready=True
  333. condvar.Signal()
  334. mutex.Unlock()
  335. End Method
  336. End Type
  337. Rem
  338. bbdoc: Create a thread
  339. returns: A new thread object.
  340. about:
  341. Creates a thread and returns a thread object.
  342. The value returned by the thread @entry routine can be later retrieved using #WaitThread.
  343. To 'close' a thread, call either #DetachThread or #WaitThread. This isn't strictly
  344. necessary as the thread will eventually be closed when it is garbage collected, however, it
  345. may be a good idea if you are creating many threads very often, as some operating systems have
  346. a limit on the number of threads that can be allocated at once.
  347. End Rem
  348. Function CreateThread:TThread( entry:Object( data:Object ),data:Object )
  349. Return TThread.Create( entry,data )
  350. End Function
  351. Rem
  352. bbdoc: Get main thread
  353. returns: A thread object representing the main application thread.
  354. End Rem
  355. Function MainThread:TThread()
  356. Return _mainThread
  357. End Function
  358. Rem
  359. bbdoc: Get current thread
  360. returns: A thread object representing the current thread.
  361. End Rem
  362. Function CurrentThread:TThread()
  363. Return TThread( _curThread.GetValue() )
  364. End Function
  365. Rem
  366. bbdoc: Detach a thread
  367. about:
  368. #DetachThread closes a thread's handle, but does not halt or otherwise affect the target thread.
  369. Once one a thread has been detached, it wil no longer be possible to use #WaitThread to get its return value.
  370. This allows the thread to run without your program having to continually check whether it has completedin order to close it.
  371. End Rem
  372. Function DetachThread( thread:TThread )
  373. thread.Detach()
  374. End Function
  375. Rem
  376. bbdoc: Wait for a thread to finish
  377. returns: The object returned by the thread entry routine.
  378. about:
  379. #WaitThread causes the calling thread to block until the target thread has completed execution.
  380. If the target thread has already completed execution, #WaitThread returns immediately.
  381. The returned object is the object returned by the thread's entry routine, as passed to #CreateThread.
  382. End Rem
  383. Function WaitThread:Object( thread:TThread )
  384. Return thread.Wait()
  385. End Function
  386. Rem
  387. bbdoc: Check if a thread is running
  388. returns: #True if @thread is still running, otherwise #False.
  389. End Rem
  390. Function ThreadRunning:Int( thread:TThread )
  391. Return thread.Running()
  392. End Function
  393. Rem
  394. bbdoc: Create thread data
  395. returns: A new thread data object.
  396. End Rem
  397. Function CreateThreadData:TThreadData()
  398. Return TThreadData.Create()
  399. End Function
  400. Rem
  401. bbdoc: Set thread data value
  402. End Rem
  403. Function SetThreadDataValue( data:TThreadData,value:Object )
  404. data.SetValue value
  405. End Function
  406. Rem
  407. bbdoc: Get thread data value
  408. End Rem
  409. Function GetThreadDataValue:Object( data:TThreadData )
  410. Return data.Getvalue()
  411. End Function
  412. Rem
  413. bbdoc: Create a mutex
  414. returns: A new mutex object
  415. End Rem
  416. Function CreateMutex:TMutex()
  417. Return TMutex.Create()
  418. End Function
  419. Rem
  420. bbdoc: Close a mutex
  421. End Rem
  422. Function CloseMutex( mutex:TMutex )
  423. mutex.Close
  424. End Function
  425. Rem
  426. bbdoc: Lock a mutex
  427. End Rem
  428. Function LockMutex( mutex:TMutex )
  429. mutex.Lock
  430. End Function
  431. Rem
  432. bbdoc: Try to lock a mutex
  433. returns: #True if @mutex was successfully locked; #False if @mutex was already locked by another thread.
  434. End Rem
  435. Function TryLockMutex:Int( mutex:TMutex )
  436. Return mutex.TryLock()
  437. End Function
  438. Rem
  439. bbdoc: Unlock a mutex
  440. End Rem
  441. Function UnlockMutex( mutex:TMutex )
  442. mutex.Unlock
  443. End Function
  444. Rem
  445. bbdoc: Create a semaphore
  446. returns: A new semaphore object
  447. End Rem
  448. Function CreateSemaphore:TSemaphore( count:Int )
  449. Return TSemaphore.Create( count )
  450. End Function
  451. Rem
  452. bbdoc: Close a semaphore
  453. End Rem
  454. Function CloseSemaphore( semaphore:TSemaphore )
  455. semaphore.Close
  456. End Function
  457. Rem
  458. bbdoc: Wait for a semaphore
  459. End Rem
  460. Function WaitSemaphore( semaphore:TSemaphore )
  461. semaphore.Wait
  462. End Function
  463. Rem
  464. bbdoc: Post a semaphore
  465. End Rem
  466. Function PostSemaphore( semaphore:TSemaphore )
  467. semaphore.Post
  468. End Function
  469. Rem
  470. bbdoc: Create a condvar
  471. returns: A new condvar object
  472. End Rem
  473. Function CreateCondVar:TCondVar()
  474. Return TCondVar.Create()
  475. End Function
  476. Rem
  477. bbdoc: Close a condvar
  478. End Rem
  479. Function CloseCondVar( condvar:TCondVar )
  480. condvar.Close
  481. End Function
  482. Rem
  483. bbdoc: Wait for a condvar
  484. End Rem
  485. Function WaitCondVar( condvar:TCondVar,mutex:TMutex )
  486. condvar.Wait mutex
  487. End Function
  488. Rem
  489. bbdoc: Signal a condvar
  490. End Rem
  491. Function SignalCondVar( condvar:TCondVar )
  492. condvar.Signal
  493. End Function
  494. Rem
  495. bbdoc: Broadcast a condvar
  496. End Rem
  497. Function BroadcastCondVar( condvar:TCondVar )
  498. condvar.Broadcast
  499. End Function
  500. Rem
  501. bbdoc: Compare and swap
  502. returns: @True if target was updated
  503. about:
  504. Atomically replace @target with @new_value if @target equals @old_value.
  505. End Rem
  506. Function CompareAndSwap:Int( target:Int Var,oldValue:Int,newValue:Int )
  507. Return bbAtomicCAS( Varptr target,oldValue,newValue )
  508. End Function
  509. Rem
  510. bbdoc: Atomic add
  511. returns: Previuous value of target
  512. about:
  513. Atomically add @value to @target.
  514. End Rem
  515. Function AtomicAdd:Int( target:Int Var,value:Int )
  516. Return bbAtomicAdd( Varptr target,value )
  517. End Function
  518. Rem
  519. bbdoc: Atomically swap values
  520. returns: The old value of @target
  521. End Rem
  522. Function AtomicSwap:Int( target:Int Var,value:Int )
  523. Repeat
  524. Local oldval:Int=target
  525. If CompareAndSwap( Varptr target,oldval,value ) Return oldval
  526. Forever
  527. End Function
  528. ?