141 Commits
Author SHA1 Message Date
server 8c3d66a7b1 Added Unconnect to connections. Allows fastmode connections to be removed 2022-12-25 21:14:34 -05:00
server f5e95b8c9f Removed print statement 2022-12-20 15:11:00 -05:00
server 2f11a80a28 Fixed > 1 which prevented tasks from being processed if only on task was in queue 2022-12-20 14:35:13 -05:00
server 8b6b56164a Merge branch 'v15.3.0' of https://github.com/rayaman/multi into v15.3.0 2022-12-10 22:48:29 -05:00
server bbc83acc0f Modified changes 2022-12-10 22:48:26 -05:00
= 0d6a9f92ad Working on getting STC working in love2d 2022-12-06 00:53:03 -05:00
= 4cf80517eb Updated docs 2022-12-06 00:03:27 -05:00
server 35a86a6cda Fixed code hanging due to thread.chain not processing varargs properly 2022-11-20 13:19:52 -05:00
server 019855d81f Fixed #args when args was a number 2022-11-20 12:31:37 -05:00
server 2a47de9fd8 Added thread.chain(...) 2022-11-20 12:17:55 -05:00
server 0d3de6e31d Fixed multiplying connections together 2022-11-07 10:01:22 -05:00
server d6d4934a7e Tests failing with connections * connections, not counting triggers properly 2022-11-06 01:00:04 -04:00
server 6369450d2f Merge branch 'v15.3.0' of https://github.com/rayaman/multi into v15.3.0 2022-11-05 23:20:47 -04:00
server a90b1d09b1 testing 2022-11-05 23:20:44 -04:00
server 92090f0a0a Merge branch 'v15.3.0' of https://github.com/rayaman/multi into v15.3.0 2022-11-05 23:19:36 -04:00
server 5cfd155241 Updated rockspec 2022-11-05 23:19:20 -04:00
server 0b2b2f9613 Merge pull request #49 from rayaman/testing_restruct
Restructure to allow submodules
2022-11-05 23:16:17 -04:00
server a5b59ee601 testing 2022-11-05 22:21:19 -04:00
server f240588edd Added changes to changelog 2022-10-31 00:09:18 -04:00
server 6abfb9c3d9 Fixed issue with opt_finding thread.hold 2022-10-30 23:54:56 -04:00
server e5ac4d3d9e Testing new optimization features 2022-10-24 23:24:24 -04:00
server 7353fde799 Working on some nice features 2022-10-06 18:36:45 -04:00
server 4c088b9080 Working on new features 2022-09-29 23:10:39 -04:00
server b727fb15b5 Reverted changes with code structure 2022-09-29 12:29:05 -04:00
server 57b4871a85 added missing files 2022-09-29 12:14:38 -04:00
server 3ae2acbd78 how did pseudothreading go away 2022-09-29 12:13:33 -04:00
server df429b617e Changed the structure of the code 2022-09-29 12:12:24 -04:00
server 0d3a7b9393 Fixed some buges with love2d support 2022-09-29 11:57:37 -04:00
server 6de93c10af Fixed issue where the Connection Host wouldn't trigger itself when a non host calls Fire 2022-09-22 23:06:45 -04:00
server a14cbb45d3 working on STC 2022-09-22 10:29:11 -04:00
server 827d3d8c45 Merge pull request #48 from rayaman/15.3.0-SystemThreadedConnections
15.3.0 system threaded connections
2022-09-22 10:28:12 -04:00
server 7bbb217018 Working with lanes, todo implement for love2d and test. 'Should work' the way it is with love2d 2022-09-21 23:16:38 -04:00
server 62e05788d2 Working on STC 2022-09-21 00:06:48 -04:00
server 772095431f Some changes to extensions, working on STC 2022-09-20 16:52:51 -04:00
server bb7fab0857 working on systemthreadedconnections 2022-09-18 13:56:00 -04:00
server 1546076c80 Protection is handled by Fire Funcction 2022-09-18 12:22:34 -04:00
server 8f3eb6d9a3 Fixed changelog order 2022-09-18 09:36:47 -04:00
server ccc4a15121 merge comflict 2022-09-18 09:35:41 -04:00
server 9050e65d93 Back and making progress 2022-09-18 09:33:13 -04:00
server 8f7183f998 Merge branch 'master' into 15.3.0-SystemThreadedConnections 2022-06-11 23:46:35 -04:00
server 3d07e774a0 Merge pull request #34 from rayaman/network_parallelism_test_branch
Network parallelism
2022-06-11 23:44:59 -04:00
server 99ba411781 Merge branch 'master' into network_parallelism_test_branch 2022-06-11 23:44:11 -04:00
server 23eaf42cad Merge branch 'v15.3.0' into 15.3.0-SystemThreadedConnections 2022-06-11 23:42:07 -04:00
server 5bca4e3383 Merge pull request #46 from rayaman/v15.3.0
V15.3.0
2022-06-11 23:41:07 -04:00
= e2bb964423 Removed print statement 2022-06-11 23:24:28 -04:00
= 0e2119a87d Added .zip to gitignore 2022-06-06 22:43:36 -04:00
= 7dfbf16bc1 Removed multi.zip 2022-06-06 22:42:53 -04:00
= bac91574a2 Changed readme, added rockspec for 15.2.1 and 15.3.0 2022-06-06 22:42:30 -04:00
server bf2f495812 Merge pull request #45 from rayaman/15.2.1
15.2.1
2022-06-06 19:29:40 -04:00
server beddecc742 Merge pull request #44 from rayaman/master
Added rockspec and modified version number
2022-06-06 19:29:09 -04:00
server 86f31bbe52 Update README.md 2022-06-06 19:28:06 -04:00
server d8f3db6972 Merge pull request #43 from rayaman/master
Merge pull request #42 from rayaman/15.2.1
2022-06-06 19:27:29 -04:00
= 494baf1e32 Added rockspec and modified version number 2022-06-06 19:26:41 -04:00
server e14fa83681 Merge pull request #42 from rayaman/15.2.1
15.2.1
2022-06-06 19:24:35 -04:00
= 278b982aff Bugfix in 15.3.0 fixed in 15.2.1 2022-06-06 19:23:31 -04:00
= 89e76ce31d Fixed issue where threaded functions were exiting improperly 2022-06-06 19:19:35 -04:00
= 831abeaccf Testing functions 2022-05-28 23:04:51 -04:00
= f74f85759b Cleaned up test files 2022-05-28 22:52:20 -04:00
server 7b70838567 Planning stuff 2022-04-23 21:07:56 -04:00
server fcc0717115 Update README.md 2022-04-19 18:46:38 -04:00
server 47d8ac30c4 Merge pull request #33 from rayaman/v15.2.0
V15.2.0
2022-04-19 18:45:52 -04:00
server 3646a1a074 Syntax changes 2022-04-19 18:45:14 -04:00
server b0ab40d410 Fixed some bugs, a little more testing needed 2022-04-19 18:39:30 -04:00
server 440995b1c8 Cleaned up rockspec file 2022-04-18 22:56:55 -04:00
server 8da4c4c1de made lanes optional(Removed it from the dependency list) 2022-04-18 22:51:38 -04:00
server 2cc2a57a46 Fixed system threads calling OnDeath incorrectly, finished full update showcase 2022-04-18 22:44:08 -04:00
server 6527dc1aaa Fixed test script to not use globally installed version and the dev version 2022-04-18 21:25:36 -04:00
server bd49805c25 testing... 2022-04-18 21:04:44 -04:00
server 40dd293bf8 Fixed issue with pesudo threading not working properly 2022-04-18 21:03:14 -04:00
server 568c95fa73 Issue with love2d system threaded functions pushstatus fixed 2022-04-16 00:02:54 -04:00
server d30ee3788e THREAD.pushStatus for lanes works, todo love 2022-04-11 23:48:45 -04:00
server 79f58a79f9 Love2d newFunction working 2022-04-10 20:00:20 -04:00
server d8aeefd202 Working on love2d threaded functions 2022-04-02 23:06:06 -04:00
server c0fb94ddbb Fixed and documented the newProcessor changes. Rockspec fix 2022-04-02 00:22:34 -04:00
server e8a3cd731d Added ST to THD namespace, old way still works 2022-04-02 00:07:06 -04:00
server 03ffb6bc0a Removed locking 2022-02-25 14:36:21 -05:00
server 4240737e00 Working on taskmanager features 2022-02-20 21:07:04 -05:00
server 5172dcdf01 Reworking the taskdetails method 2022-02-17 10:00:55 -05:00
server fc18a303dd Fixed issue with how the thread scheduler spawned threads 2022-02-15 21:47:07 -05:00
server 04d5500374 Fixed issue with the new thread scheduler(again) connections and hold get a buff 2022-02-15 15:11:28 -05:00
server 72e24e8a9b Added connection:hasConnections() 2022-02-14 18:00:02 -05:00
server 48bba84c08 Fix issue where I forgot to implement the handler for thread.yield 2022-02-13 00:16:00 -05:00
server e9a0e7bbf7 Fixed an issue with the new thread namespace 2022-02-09 22:19:27 -05:00
server 264867a0da Fixed issue with threads not returning values properly 2022-02-09 19:29:06 -05:00
server 3f046afaa1 Fixed: missing a yield 2022-02-09 17:05:30 -05:00
server 2acce5001d Small issue with functions attached to processes 2022-02-09 16:30:19 -05:00
server 78cd15681a Removed actions for now 2022-02-08 22:51:46 -05:00
server 3401a8ac61 fixing issue with actions 2022-02-08 22:48:27 -05:00
server 19ac257204 Testing actions 2022-02-08 22:47:16 -05:00
server c14a469069 Each processor has it's own thread handler, all processes now trigger the default thread handler. 2022-02-08 22:40:38 -05:00
server 03cea2d71a Processors are working nicely, mostly done with the library 2022-02-05 10:56:03 -05:00
server 593bfd0d8c Threads now working, can create many more threads without a performance hit 2022-02-05 00:55:11 -05:00
server bf60a354d4 So the bug wasn't a bug all along 2022-02-04 17:27:13 -05:00
server 6c73220a52 working on scheduler, nothing fix yet 2022-01-31 17:11:14 -05:00
server c3a9ddfdbd Reverted the extra space 2022-01-31 10:51:44 -05:00
server e05f2ea400 last test 2022-01-31 10:50:45 -05:00
server a60aae02c6 Cleanup spaces 2022-01-31 10:45:26 -05:00
server 207c5b8d69 test2 2022-01-31 09:52:43 -05:00
server a9111f2fa3 test 2022-01-31 09:49:12 -05:00
server b572bf218d Still debugging, not sure what is causing the thread to not yield properly 2022-01-31 09:47:37 -05:00
server 49c0bd3930 Fixing issues with the new thread scheduler, nested yields need handling 2022-01-31 08:31:38 -05:00
server cdb4bfda11 Error handling not working if its on the first step 2022-01-28 17:50:19 -05:00
server 3fbead60d9 connections working, todo: error catching and return catching 2022-01-26 16:52:17 -05:00
server 2b122f5c77 scheduler is much faster, missing connection holding and error handling 2022-01-26 00:03:32 -05:00
server 472d1748ee Working on thread scheduler rework 2022-01-24 14:25:23 -05:00
server 47178dd3b3 Started to work on the scheduler rework 2022-01-24 09:00:51 -05:00
server 3fcba8825b Reworked priorities 2022-01-23 17:23:32 -05:00
server e194a06427 Cleaned up the mainloop/umanager 2022-01-23 12:14:50 -05:00
server 32f7b4492b Improving performance in the mainloop 2022-01-22 23:34:15 -05:00
server 913745a1bc Merge branch 'v15.2.0' of https://github.com/rayaman/multi into v15.2.0 2022-01-20 13:07:01 -05:00
server 889dc6ca68 Removed unneeded files 2022-01-20 13:06:53 -05:00
server 2805137648 Merge branch 'master' into v15.2.0 2022-01-20 12:31:09 -05:00
server f7167cf972 Current progress in v15.2.0 updated ignore file 2022-01-20 12:29:39 -05:00
server 9e1ecb3583 Testing... 2022-01-20 09:53:56 -05:00
server b9b9b51d12 Taking testing seriously 2022-01-20 09:49:48 -05:00
server a708fb3f83 testing stuff 2022-01-19 23:13:58 -05:00
server 4335f3ed14 Testing 2022-01-19 23:12:16 -05:00
server 8580d92c9c Fixing issues with priority 2022-01-19 23:09:47 -05:00
server f1f6e30a98 testing 2022-01-19 13:41:29 -05:00
server 6c1e9f26f0 Reworking the loops 2022-01-18 23:39:17 -05:00
server d98f353936 Tweaked processor object, added lightloop and lmanager 2022-01-17 23:23:56 -05:00
server 14c8665910 Update README.md 2022-01-16 16:30:45 -05:00
server f7452db3ec spaces to tabs 2022-01-16 16:30:03 -05:00
server 588923e1b7 spaces to tabs 2022-01-16 16:26:37 -05:00
server 4877f64ca1 Fix some bugs, added connection/thread tests 2022-01-16 16:18:17 -05:00
server b8b31253d4 Added key feature 2022-01-11 23:16:33 -05:00
server af4672245e Removed some tests 2022-01-11 23:04:35 -05:00
server 609613dbe9 Fixed lua 5.4 issue and the taskstatus 2022-01-11 18:59:53 -05:00
server b16593425b Fixed typo in changes.md 2022-01-09 23:32:54 -05:00
server 997ea48b54 Writing tests, fixed some bugs with the library, testing luajit support 2022-01-09 23:23:54 -05:00
server 537dcf0db1 Working on performance 2022-01-04 18:01:02 -05:00
server b74a6c006e Updated lanes integration 2022-01-02 12:18:35 -05:00
server b3453d028c Fixed the lanes issue? 2022-01-02 11:41:39 -05:00
server 6842147522 Updated gitignore 2022-01-02 11:25:42 -05:00
server de34b9dc59 Merge pull request #32 from rayaman/v16.0.0
Updated license
2022-01-01 23:21:58 -05:00
server dff19d865f Updated license 2022-01-01 23:20:48 -05:00
server 544aa78d70 Updated code 2021-12-24 22:47:38 -05:00
server 91d0b5f7be added some spaces 2021-12-19 01:05:34 -05:00
server 27e03a2546 bug fixing should be done 2021-12-18 12:55:20 -05:00
server 7dbcd01c33 Merge pull request #31 from rayaman/V15.2.0
working on 16.0
2021-12-18 12:42:58 -05:00
server cc20914391 working on 1.16 2021-12-18 12:42:14 -05:00
42 changed files with 3819 additions and 3407 deletions
+1 -14
View File
@@ -1,15 +1,2 @@
test2.lua
*.mp3
*.exe
*.dll
lanestestclient.lua
lanestest.lua
sample-node.lua
sample-master.lua
Ayn Rand - The Virtue of Selfishness-Mg4QJheclsQ.m4a
Atlas Shrugged by Ayn Rand Audiobook-9s2qrEau63E.webm
test.lua
test.lua
*.code-workspace *.code-workspace
*.dat lua5.4/*
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2021 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+45 -26
View File
@@ -1,59 +1,78 @@
# Multi Version: 15.1.0 Hold the thread # Multi Version: 15.3.0 A world of Connections
**Key Changes** **Key Changes**
- thread.hold has been updated to allow all variants to work as well as some new features. Check the changelog or documentation for more info. - SystemThreadedConnections
- multi:newProccesor() Creates a process that acts like the multi namespace that can be managed independently from the mainloop. - Restructured the directory structure of the repo (Allows for keeping multi as a submodule and being able to require it as is)
- Connections can be added together - Bug fixes
Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it! Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it!
My multitasking library for lua. It is a pure lua binding, with exceptions of the integrations and the love2d compat. My multitasking library for lua. It is a pure lua binding, with exceptions of the integrations.
</br>
Progress is being made in [v15.4.0](https://github.com/rayaman/multi/tree/v15.4.0)
---
</br>
INSTALLING INSTALLING
---------- ----------
Links to dependencies: Link to optional dependencies:
[lanes](https://github.com/LuaLanes/lanes) - [lanes](https://github.com/LuaLanes/lanes)
- [love2d](https://love2d.org/)
To install copy the multi folder into your environment and you are good to go</br> To install copy the multi folder into your environment and you are good to go</br>
If you want to use the system threads, then you'll need to install lanes! If you want to use the system threads, then you'll need to install lanes or love2d game engine!
**or** use luarocks `luarocks install multi`
Going forward I will include a Release zip for love2d. ```
**The Network Manager rework is currently being worked on and the old version is not included in this version.** luarocks install multi
```
Discord Discord
------- -------
Have a question? Or need realtime assistance? Feel free to join the discord!</br> Have a question or need realtime assistance? Feel free to join the discord!</br>
https://discord.gg/U8UspuA</br> https://discord.gg/U8UspuA
Planned features/TODO Planned features/TODO
--------------------- ---------------------
- [x] ~~Finish Documentation~~ Finished - [ ] Create test suite (In progress, mostly done)
- [ ] Create test suite
- [ ] Network Parallelism rework - [ ] Network Parallelism rework
Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md)</br> Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md)
----- -----
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
GLOBAL, THREAD = require("multi.integration.threading"):init() GLOBAL, THREAD = require("multi.integration.threading"):init()
multi:newSystemThread("System Thread",function() multi:newSystemThread("System Thread",function()
while true do while true do
THREAD.sleep(1) THREAD.sleep(.1)
print("World!") io.write(" World")
end THREAD.kill()
end
end) end)
multi:newThread("Coroutine Based Thread",function() multi:newThread("Coroutine Based Thread",function()
while true do while true do
print("Hello") io.write("Hello")
thread.sleep(1) thread.sleep(.1)
end thread.kill()
end
end) end)
multi:newTLoop(function(loop)
print("!")
loop:Destroy()
os.exit()
end,.3)
multi:mainloop() multi:mainloop()
--[[ --[[
while true do while true do
multi:uManager() multi:uManager()
end end
]] ]]
``` ```
+510 -83
View File
@@ -1,15 +1,489 @@
# Changelog # Changelog
Table of contents Table of contents
--- ---
[Update 15.1.0 - Hold the thread!](#update-1510---hold-the-thread)</br>[Update 15.0.0 - The art of faking it](#update-1500---the-art-of-faking-it)</br>[Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)</br>[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</br>[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) [Update 15.3.0 - A world of connections](#update-1530---a-world-of-connections)</br>
[Update 15.2.1 - Bug fix](#update-1521---bug-fix)</br>
[Update 15.2.0 - Upgrade Complete](#update-1520---upgrade-complete)</br>[Update 15.1.0 - Hold the thread!](#update-1510---hold-the-thread)</br>[Update 15.0.0 - The art of faking it](#update-1500---the-art-of-faking-it)</br>[Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)</br>[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</br>[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
# Update 15.3.0 - A world of Connections
Full Update Showcase
```lua
multi, thread = require("multi"):init{print=true}
GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
local conn = multi:newSystemThreadedConnection("conn"):init()
multi:newSystemThread("Thread_Test_1",function()
local multi, thread = require("multi"):init()
local conn = GLOBAL["conn"]:init()
conn(function()
print(THREAD:getName().." was triggered!")
end)
multi:mainloop()
end)
multi:newSystemThread("Thread_Test_2",function()
local multi, thread = require("multi"):init()
local conn = GLOBAL["conn"]:init()
conn(function(a,b,c)
print(THREAD:getName().." was triggered!",a,b,c)
end)
multi:newAlarm(2):OnRing(function()
print("Fire 2!!!")
conn:Fire(4,5,6)
THREAD.kill()
end)
multi:mainloop()
end)
conn(function(a,b,c)
print("Mainloop conn got triggered!",a,b,c)
end)
alarm = multi:newAlarm(1)
alarm:OnRing(function()
print("Fire 1!!!")
conn:Fire(1,2,3)
end)
alarm = multi:newAlarm(3):OnRing(function()
multi:newSystemThread("Thread_Test_3",function()
local multi, thread = require("multi"):init()
local conn = GLOBAL["conn"]:init()
conn(function(a,b,c)
print(THREAD:getName().." was triggered!",a,b,c)
end)
multi:newAlarm(2):OnRing(function()
print("Fire 3!!!")
conn:Fire(7,8,9)
end)
multi:mainloop()
end)
end)
multi:newSystemThread("Thread_Test_4",function()
local multi, thread = require("multi"):init()
local conn = GLOBAL["conn"]:init()
local conn2 = multi:newConnection()
multi:newAlarm(2):OnRing(function()
conn2:Fire()
end)
multi:newThread(function()
print("Conn Test!")
thread.hold(conn + conn2)
print("It held!")
end)
multi:mainloop()
end)
multi:mainloop()
```
Added
---
- `multi:newConnection():Unconnect(conn_link)` Fastmode previously didn't have the ability to be unconnected to. This method works with both fastmode and non fastmode. `fastMode` will be made the default in v16.0.0 (This is a breaking change for those using the Destroy method, use this time to migrate to using `Unconnect()`)
- `thread.chain(...)` allows you to chain `thread.hold(FUNCTIONs)` together
```lua
while true do
thread.chain(hold_function_1, hold_function_2)
end
```
If the first function returns true, it moves on to the next one. if expanded it follows:
```lua
while true do
thread.hold(hold_function_1)
thread.hold(hold_function_2)
end
```
- Experimental option to multi settings: `findopt`. When set to `true` it will print out a message when certain pattern are used with this library. For example if an anonymous function is used in thread.hold() within a loop. The library will trigger a message alerting you that this isn't the most performant way to use thread.hold().
- `multi:newSystemThreadedConnection()`
Allows one to trigger connection events across threads. Works like how any connection would work. Supports all of the features, can even be `added` with non SystemThreadedConnections as demonstrated in the full showcase.
- `multi:newConnection():SetHelper(func)`
Sets the helper function that the connection object uses when creating connection links.
- `multi.ForEach(table, callback_function)`
Loops through the table and calls callback_function with each element of the array.
- If a name is not supplied when creating threads and threaded objects; a name is randomly generated. Unless sending through an established channel/queue you might not be able to easily init the object.
Changed
---
- Internally all `OnError` events are now connected to with multi.print, you must pass `print=true` to the init settings when initializing the multi object. `require("multi"):init{print=true}`
- All actors now use fastmode on connections
- Performance enhancement with processes that are pumped. Instead of automatically running, by suppressing the creation of an internal loop object that would manage the process, we bypass that freeing up memory and adding a bit more speed.
- `Connection:fastMode() or Connection:SetHelper()` now returns a reference to itself
- `Connection:[connect, hasConnections, getConnection]` changed to be `Connection:[Connect, HasConnections, getConnections]`. This was done in an attempt to follow a consistent naming scheme. The old methods still will work to prevent old code breaking.
- `Connections when added(+) together now act like 'or', to get the 'and' feature multiply(*) them together.`
**Note:** This is a potentially breaking change for using connections.
```lua
multi, thread = require("multi"):init{print=true}
-- GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
local conn1, conn2, conn3 = multi:newConnection(), multi:newConnection(), multi:newConnection()
thread:newThread(function()
print("Awaiting status")
thread.hold(conn1 + (conn2 * conn3))
print("Conn or Conn2 and Conn3")
end)
multi:newAlarm(1):OnRing(function()
print("Conn")
conn1:Fire()
end)
multi:newAlarm(2):OnRing(function()
print("Conn2")
conn2:Fire()
end)
multi:newAlarm(3):OnRing(function()
print("Conn3")
conn3:Fire()
end)
```
Removed
---
- Connection objects methods removed:
- holdUT(), HoldUT() -- With the way `thread.hold(conn)` interacts with connections this method was no longer needed. To emulate this use `multi.hold(conn)`. `multi.hold()` is able to emulate what `thread.hold()` outside of a thread, albeit with some drawbacks.
Fixed
---
- SystemThreaded Objects variables weren't consistent.
- Issue with connections being multiplied only being able to have a combined fire once
ToDo
---
- Work on network parallelism (I am really excited to start working on this. Not because it will have much use, but because it seems like a cool addition/project to work on. I just need time to actually do work on stuff)
# Update 15.2.1 - Bug fix
Fixed issue #41
---
# Update 15.2.0 - Upgrade Complete
Full Update Showcase
```lua
package.path = "./?/init.lua;"..package.path
multi, thread = require("multi"):init{print=true}
GLOBAL, THREAD = require("multi.integration.threading"):init()
-- Using a system thread, but both system and local threads support this!
-- Don't worry if you don't have lanes or love2d. PesudoThreading will kick in to emulate the threading features if you do not have access to system threading.
func = THREAD:newFunction(function(count)
print("Starting Status test: ",count)
local a = 0
while true do
a = a + 1
THREAD.sleep(.1)
-- Push the status from the currently running threaded function to the main thread
THREAD.pushStatus(a,count)
if a == count then break end
end
return "Done"
end)
thread:newThread("test",function()
local ret = func(10)
ret.OnStatus(function(part,whole)
print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%")
end)
print("TEST",func(5).wait())
-- The results from the OnReturn connection is passed by thread.hold
print("Status:",thread.hold(ret.OnReturn))
print("Function Done!")
end).OnError(function(...)
print("Error:",...)
end)
local ret = func(10)
local ret2 = func(15)
local ret3 = func(20)
local s1,s2,s3 = 0,0,0
ret.OnError(function(...)
print("Error:",...)
end)
ret2.OnError(function(...)
print("Error:",...)
end)
ret3.OnError(function(...)
print("Error:",...)
end)
ret.OnStatus(function(part,whole)
s1 = math.ceil((part/whole)*1000)/10
print(s1)
end)
ret2.OnStatus(function(part,whole)
s2 = math.ceil((part/whole)*1000)/10
print(s2)
end)
ret3.OnStatus(function(part,whole)
s3 = math.ceil((part/whole)*1000)/10
print(s3)
end)
loop = multi:newTLoop()
function loop:testing()
print("testing haha")
end
loop:Set(1)
t = loop:OnLoop(function()
print("Looping...")
end):testing()
local proc = multi:newProcessor("Test")
local proc2 = multi:newProcessor("Test2")
local proc3 = proc2:newProcessor("Test3")
proc.Start()
proc2.Start()
proc3.Start()
proc:newThread("TestThread_1",function()
while true do
thread.sleep(1)
end
end)
proc:newThread("TestThread_2",function()
while true do
thread.sleep(1)
end
end)
proc2:newThread("TestThread_3",function()
while true do
thread.sleep(1)
end
end)
thread:newThread(function()
thread.sleep(1)
local tasks = multi:getStats()
for i,v in pairs(tasks) do
print("Process: " ..i.. "\n\tTasks:")
for ii,vv in pairs(v.tasks) do
print("\t\t"..vv:getName())
end
print("\tThreads:")
for ii,vv in pairs(v.threads) do
print("\t\t"..vv:getName())
end
end
thread.sleep(10) -- Wait 10 seconds then kill the process!
os.exit()
end)
multi:mainloop()
```
Added:
---
- `multi:getStats()`
- Returns a structured table where you can access data on processors there tasks and threads:
```lua
-- Upon calling multi:getStats() the table below is returned
get_Stats_Table {
proc_1 -- table
proc_2 -- table
...
proc_n -- table
}
proc_Table {
tasks = {alarms,steps,loops,etc} -- All multi objects
threads = {thread_1,thread_2,thread_3,etc} -- Thread objects
}
-- Refer to the objects documentation to see how you can interact with them
```
- Reference the Full update showcase for the method in action
- `multi:newProcessor(name, nothread)`
- If no thread is true auto sets the processor as Active, so proc.run() will start without the need for proc.Start()
- `multi:getProcessors()`
- Returns a list of all processors
- `multi:getName()`
- Returns the name of a processor
- `multi:getFullName()`
- Returns the fullname/entire process tree of a process
- Processors can be attached to processors
- `multi:getTasks()`
- Returns a list of all non thread based objects (loops, alarms, steps, etc)
- `multi:getThreads()`
- Returns a list of all threads on a process
- `multi:newProcessor(name, nothread).run()`
- New function run to the processor object to
- `multi:newProcessor(name, nothread):newFunction(func, holdme)`
- Acts like thread:newFunction(), but binds the execution of that threaded function to the processor
- `multi:newTLoop()` member functions
- `TLoop:Set(set)` - Sets the time to wait for the TLoop
- `multi:newStep()` member functions
- `Step:Count(count)` - Sets the amount a step should count by
- `multi:newTStep()` member functions
- `TStep:Set(set)` - Sets the time to wait for the TStep
Changed:
---
- `thread.hold(connectionObj)` now passes the returns of that connection to `thread.hold()`! See Exampe below:
```lua
multi, thread = require("multi"):init()
func = thread:newFunction(function(count)
local a = 0
while true do
a = a + 1
thread.sleep(.1)
thread.pushStatus(a,count)
if a == count then break end
end
return "Done", 1, 2, 3
end)
thread:newThread("test",function()
local ret = func(10)
ret.OnStatus(function(part,whole)
print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%")
end)
print("Status:",thread.hold(ret.OnReturn))
print("Function Done!")
os.exit()
end).OnError(function(...)
print("Error:",...)
end)
multi:mainloop()
```
Output:
```
Ret1: 10%
Ret1: 20%
Ret1: 30%
Ret1: 40%
Ret1: 50%
Ret1: 60%
Ret1: 70%
Ret1: 80%
Ret1: 90%
Ret1: 100%
Status: Done 1 2 3 nil nil nil nil nil nil nil nil nil nil nil nil
Function Done!
```
- Modified how threads are handled internally. This changes makes it so threads "regardless of amount" should not impact performance. What you do in the threads might. This change was made by internally only processing one thread per step per processor. If you have 10 processors that are all active expect one step to process 10 threads. However if one processor has 10 threads each step will only process one thread. Simply put each addition of a thread shouldn't impact performance as it did before.
- Moved `multi:newThread(...)` into the thread interface (`thread:newThread(...)`), code using `multi:newThread(...)` will still work. Also using `process:newThread(...)` binds the thread to the process, meaning if the process the thread is bound to is paused so is the thread.
- multi:mainloop(~~settings~~)/multi:uManager(~~settings~~) no longer takes a settings argument, that has been moved to multi:init(settings)
| Setting | Description |
---|---
print | When set to true parts of the library will print out updates otherwise no internal printing will be done
priority | When set to true, the library will prioritize different objects based on their priority
- `multi:newProcessor(name,nothread)` The new argument allows you to tell the system you won't be using the Start() and Stop() functions, rather you will handle the process yourself. Using the proc.run() function. This function needs to be called to pump the events.
- Processors now also use lManager instead of uManager.
- `multi.hold(n,opt)` now supports an option table like thread.hold does.
- Connection Objects now pass on the parent object if created on a multiobj. This was to allow chaining to work properly with the new update
```lua
multi,thread = require("multi"):init()
loop = multi:newTLoop()
function loop:testing()
print("testing haha")
end
loop:Set(1)
t = loop:OnLoop(function()
print("Looping...")
end):testing()
multi:mainloop()
--[[Returns as expected:
testing haha
Looping...
Looping...
Looping...
...
Looping...
Looping...
Looping...
]]
```
While chaining on the OnSomeEventMethod() wasn't really a used feature, I still wanted to keep it just incase someone was relying on this working. And it does have it uses
- All Multi Objects now use Connection objects
`multiobj:OnSomeEvent(func)` or `multiobj.OnSomeEvent(func)`
- Connection Objects no longer Fire with syntax sugar when attached to an object:
`multiobj:OnSomeEvent(...)` No longer triggers the Fire event. As part of the update to make all objects use connections internally this little used feature had to be scrapped!
- multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit)
Removed:
---
- `multi:getTasksDetails()` Remade completely and now called `multi:getStats()`
- `multi:getError()` Removed when setting protect was removed
- `multi:FreeMainEvent()` The new changes with connections make's this function unnecessary
- `multi:OnMainConnect(func)` See above
- `multi:connectFinal(func)` See above
- `multi:lightloop()` Cleaned up the mainloop/uManager method, actually faster than lightloop (Which should have been called liteloop)
- `multi:threadloop()` See above for reasons
- `multi setting: protect` This added extra complexity to the mainloop and not much benefit. If you feel a function will error use pcall yourself. This saves a decent amount of cycles, about 6.25% increase in performance.
- `multi:GetParentProcess()` use `multi.getCurrentProcess()` instead
- priority scheme 2, 3 and auto-priority have been removed! Only priority scheme 1 actually performed in a reasonable fashion so that one remained.
- `multi:newFunction(func)`
- `thread:newFunction(func)` Has many more features and replaces what multi:newFunction did
- `multi.holdFor()` Now that multi.hold takes the option table that thread.hold has this feature can be emulated using that.
- Calling Fire on a connection no longer returns anything! Now that internal features use connections, I noticed how slow connections are and have increased their speed quite a bit. From 50,000 Steps per seconds to almost 7 Million. All other features should work just fine. Only returning values has been removed
Fixed:
---
- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seemed to be related to my filesystem, since remounting the drive caused the issue to stop. (Windows)
- [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not being up to date with threaded functions
- Issue where gettasksdetails() would try to process a destroyed object causing it to crash
- Issue with multi.hold() not pumping the mainloop and only the scheduler
ToDo:
---
- Work on network parallelism
# Update 15.1.0 - Hold the thread! # Update 15.1.0 - Hold the thread!
Full Update Showcase Full Update Showcase
```lua ```lua
package.path = "./?/init.lua;"..package.path local multi,thread = require("multi"):init()
multi,thread = require("multi"):init()
func = thread:newFunction(function(count) func = thread:newFunction(function(count)
local a = 0 local a = 0
@@ -98,17 +572,17 @@ multi:mainloop()
Added: Added:
--- ---
## multi:newSystemThreadedJobQueue(n) isEmpty() - multi:newSystemThreadedJobQueue(n)
- returns true if the queue is empty, false if there are items in the queue. `queue:isEmpty()`
Returns true if the queue is empty, false if there are items in the queue.
**Note:** a queue might be empty, but the job may still be running and not finished yet! Also if a registered function is called directly instead of pushed, it will not reflect inside the queue until the next cycle! **Note:** a queue might be empty, but the job may still be running and not finished yet! Also if a registered function is called directly instead of pushed, it will not reflect inside the queue until the next cycle!
Example: Example:
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path local multi,thread = require("multi"):init()
package.cpath = [[C:\Program Files (x86)\Lua\5.1\systree\lib\lua\5.1\?.dll;C:\Program Files (x86)\Lua\5.1\systree\lib\lua\5.1\?\core.dll;]] ..package.cpath
multi,thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available
jq = multi:newSystemThreadedJobQueue(5) -- Job queue with 4 worker threads jq = multi:newSystemThreadedJobQueue(5) -- Job queue with 4 worker threads
@@ -153,8 +627,7 @@ multi:mainloop()
## multi:newProcessor(name) ## multi:newProcessor(name)
```lua ```lua
package.path = "./?/init.lua;"..package.path local multi,thread = require("multi"):init()
multi,thread = require("multi"):init()
-- Create a processor object, it works a lot like the multi object -- Create a processor object, it works a lot like the multi object
sandbox = multi:newProcessor() sandbox = multi:newProcessor()
@@ -227,8 +700,7 @@ Can be chained as long as you want! See example below
Example: Example:
```lua ```lua
package.path = "./?/init.lua;"..package.path local multi,thread = require("multi"):init()
multi,thread = require("multi"):init()
func = thread:newFunction(function(count) func = thread:newFunction(function(count)
local a = 0 local a = 0
@@ -283,8 +755,7 @@ Changed:
holdMe(set) | Sets the holdme argument that existed at function creation holdMe(set) | Sets the holdme argument that existed at function creation
```lua ```lua
package.path = "./?/init.lua;"..package.path local multi, thread = require("multi"):init()
multi, thread = require("multi"):init()
test = thread:newFunction(function(a,b) test = thread:newFunction(function(a,b)
thread.sleep(1) thread.sleep(1)
@@ -378,8 +849,7 @@ ToDo
Full Update Showcase Full Update Showcase
--- ---
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path local multi,thread = require("multi"):init()
multi,thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available
jq = multi:newSystemThreadedJobQueue(4) -- Job queue with 4 worker threads jq = multi:newSystemThreadedJobQueue(4) -- Job queue with 4 worker threads
@@ -413,6 +883,7 @@ multi:mainloop()
Note: Note:
--- ---
This was supposed to be released over a year ago, but work and other things got in my way. Pesudo Threading now works. The goal of this is so you can write modules that can be scaled up to utilize threading features when available. This was supposed to be released over a year ago, but work and other things got in my way. Pesudo Threading now works. The goal of this is so you can write modules that can be scaled up to utilize threading features when available.
Added: Added:
--- ---
- multi:newISOThread(name,func,env) - multi:newISOThread(name,func,env)
@@ -448,7 +919,6 @@ Todo:
Full Update Showcase Full Update Showcase
--- ---
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
local multi,thread = require("multi"):init() local multi,thread = require("multi"):init()
-- Testing destroying and fixed connections -- Testing destroying and fixed connections
@@ -515,7 +985,6 @@ Fixed:
- Issue with connections not returning a handle for managing a specific conn object. - Issue with connections not returning a handle for managing a specific conn object.
- Issue with connections where connection chaining wasn't working properly. This has been addressed. - Issue with connections where connection chaining wasn't working properly. This has been addressed.
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
local multi,thread = require("multi"):init() local multi,thread = require("multi"):init()
test = multi:newConnection() test = multi:newConnection()
test(function(hmm) test(function(hmm)
@@ -568,7 +1037,6 @@ Full Update Showcase
--- ---
Something I plan on doing each version going forward Something I plan on doing each version going forward
```lua ```lua
package.path="?.lua;?/init.lua;?.lua;"..package.path
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.lanesManager"):init() GLOBAL,THREAD = require("multi.integration.lanesManager"):init()
serv = multi:newService(function(self,data) serv = multi:newService(function(self,data)
@@ -790,19 +1258,21 @@ Added:
-- If the created function encounters an error, it will return nil, the error message! -- If the created function encounters an error, it will return nil, the error message!
- special variable multi.NIL was added to allow error handling in threaded functions. - special variable multi.NIL was added to allow error handling in threaded functions.
-- multi.NIL can be used in to force a nil value when using thread.hold() -- multi.NIL can be used in to force a nil value when using thread.hold()
- All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features. **Note:** these functions are local to the function! And are only converted if they aren't set as local! Otherwise the function - All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features.
**Note:** these functions are local to the function! And are only converted if they aren't set as local! Otherwise the function is converted into a threaded function
- lanes threads can now have their priority set using: sThread.priority = - lanes threads can now have their priority set using: sThread.priority =
-- thread.Priority_Core - thread.Priority_Core
-- thread.Priority_High - thread.Priority_High
-- thread.Priority_Above_Normal - thread.Priority_Above_Normal
-- thread.Priority_Normal - thread.Priority_Normal
-- thread.Priority_Below_Normal - thread.Priority_Below_Normal
-- thread.Priority_Low - thread.Priority_Low
-- thread.Priority_Idle - thread.Priority_Idle
- thread.hold() and multi.hold() now accept connections as an argument. See example below - thread.hold() and multi.hold() now accept connections as an argument. See example below
```lua ```lua
package.path = "./?/init.lua;"..package.path
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
conn = multi:newConnection() conn = multi:newConnection()
multi:newThread(function() multi:newThread(function()
@@ -833,7 +1303,6 @@ end)
thread newFunction using auto convert thread newFunction using auto convert
```lua ```lua
package.path = "./?/init.lua;" .. package.path
multi, thread = require("multi").init() multi, thread = require("multi").init()
a=5 a=5
multi:newThread("Test",function() multi:newThread("Test",function()
@@ -871,7 +1340,7 @@ Changed:
--- ---
- Connections connect function can now chain connections - Connections connect function can now chain connections
```lua ```lua
package.path = "./?/init.lua;"..package.path
local multi, thread = require("multi").init() local multi, thread = require("multi").init()
test = multi:newConnection() test = multi:newConnection()
test(function(a) test(function(a)
@@ -1069,7 +1538,6 @@ Added:
- STC: FireTo(id,...) — Described above. - STC: FireTo(id,...) — Described above.
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
local multi = require("multi") local multi = require("multi")
conn = multi:newConnector() conn = multi:newConnector()
conn.OnTest = multi:newConnection() conn.OnTest = multi:newConnection()
@@ -1141,7 +1609,6 @@ Going forward:
Example Example
--- ---
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
multi = require("multi") multi = require("multi")
GLOBAL, THREAD = require("multi.integration.lanesManager").init() GLOBAL, THREAD = require("multi.integration.lanesManager").init()
jq = multi:newSystemThreadedJobQueue() jq = multi:newSystemThreadedJobQueue()
@@ -1203,7 +1670,7 @@ L: 6543
I: 1635 I: 1635
~n=n*4 ~n=n*4
``` ```
P3 Ignores using a basic funceion and instead bases its processing time on the amount of cpu time is there. If cpu-time is low and a process is set at a lower priority it will get its time reduced. There is no formula, at idle almost all process work at the same speed! P3 Ignores using a basic function and instead bases its processing time on the amount of cpu time is there. If cpu-time is low and a process is set at a lower priority it will get its time reduced. There is no formula, at idle almost all process work at the same speed!
``` ```
C: 2120906 C: 2120906
H: 2120906 H: 2120906
@@ -1218,10 +1685,10 @@ Auto Priority works by seeing what should be set high or low. Due to lua not hav
**Improved:** **Improved:**
- Performance at the base level has been doubled! On my machine benchmark went from ~9mil to ~20 mil steps/s. - Performance at the base level has been doubled! On my machine benchmark went from ~9mil to ~20 mil steps/s.
Note: If you write slow code this library's improbements wont make much of a difference. Note: If you write slow code this library's improvements wont make much of a difference.
- Loops have been optimised as well! Being the most used objects I felt they needed to be made as fast as possible - Loops have been optimised as well! Being the most used objects I felt they needed to be made as fast as possible
I usually give an example of the changes made, but this time I have an explantion for multi.nextStep(). It's not an entirely new feature since multi:newJob() does something like this, but is completely different. nextStep addes a function that is executed first on the next step. If multiple things are added to next step, then they will be executed in the order that they were added. I usually give an example of the changes made, but this time I have an explantion for `multi.nextStep()`. It's not an entirely new feature since multi:newJob() does something like this, but is completely different. nextStep adds a function that is executed first on the next step. If multiple things are added to next step, then they will be executed in the order that they were added.
Note: Note:
The upper limit of this libraries performance on my machine is ~39mil. This is simply a while loop counting up from 0 and stops after 1 second. The 20mil that I am currently getting is probably as fast as it can get since its half of the max performance possible, and each layer I have noticed that it doubles complexity. Throughout the years with this library I have seen massive improvements in speed. In the beginning we had only ~2000 steps per second. Fast right? then after some tweaks we went to about 300000 steps per second, then 600000. Some more tweaks brought me to ~1mil steps per second, then to ~4 mil then ~9 mil and now finally ~20 mil... the doubling effect that i have now been seeing means that odds are I have reach the limit. I will aim to add more features and optimize individule objects. If its possible to make the library even faster then I will go for it. The upper limit of this libraries performance on my machine is ~39mil. This is simply a while loop counting up from 0 and stops after 1 second. The 20mil that I am currently getting is probably as fast as it can get since its half of the max performance possible, and each layer I have noticed that it doubles complexity. Throughout the years with this library I have seen massive improvements in speed. In the beginning we had only ~2000 steps per second. Fast right? then after some tweaks we went to about 300000 steps per second, then 600000. Some more tweaks brought me to ~1mil steps per second, then to ~4 mil then ~9 mil and now finally ~20 mil... the doubling effect that i have now been seeing means that odds are I have reach the limit. I will aim to add more features and optimize individule objects. If its possible to make the library even faster then I will go for it.
@@ -1235,10 +1702,9 @@ Fixed:
Changed: Changed:
--- ---
- thread.hold() now returns the arguments that were pass by the event function - thread.hold() now returns the arguments that were pass by the event function
- event objexts now contain a copy of what returns were made by the function that called it in a table called returns that exist inside of the object - event objects now contain a copy of what returns were made by the function that called it in a table called returns that exist inside of the object
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
multi = require("multi") multi = require("multi")
local a = 0 local a = 0
multi:newThread("test",function() multi:newThread("test",function()
@@ -1335,7 +1801,6 @@ Now there is a little trick you can do. If you combine both networkmanager and s
**NodeManager.lua** **NodeManager.lua**
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
multi = require("multi") multi = require("multi")
local GLOBAL, THREAD = require("multi.integration.lanesManager").init() local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
nGLOBAL = require("multi.integration.networkManager").init() nGLOBAL = require("multi.integration.networkManager").init()
@@ -1354,7 +1819,6 @@ Side note: I had a setting called cross talk that would allow nodes to talk to e
**Node.lua** **Node.lua**
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
multi = require("multi") multi = require("multi")
local GLOBAL, THREAD = require("multi.integration.lanesManager").init() local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
nGLOBAL = require("multi.integration.networkManager").init() nGLOBAL = require("multi.integration.networkManager").init()
@@ -1376,10 +1840,8 @@ multi:mainloop(settings)
**Master.lua** **Master.lua**
```lua ```lua
-- set up the package
package.path="?/init.lua;?.lua;"..package.path
-- Import the libraries -- Import the libraries
multi = require("multi") local multi = require("multi")
local GLOBAL, THREAD = require("multi.integration.lanesManager").init() local GLOBAL, THREAD = require("multi.integration.lanesManager").init()
nGLOBAL = require("multi.integration.networkManager").init() nGLOBAL = require("multi.integration.networkManager").init()
-- Act as a master node -- Act as a master node
@@ -1549,7 +2011,6 @@ Added:
Example of threaded connections Example of threaded connections
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
local GLOBAL,THREAD=require("multi.integration.lanesManager").init() local GLOBAL,THREAD=require("multi.integration.lanesManager").init()
multi:newSystemThread("Test_Thread_1",function() multi:newSystemThread("Test_Thread_1",function()
connOut = THREAD.waitFor("ConnectionNAMEHERE"):init() connOut = THREAD.waitFor("ConnectionNAMEHERE"):init()
@@ -1586,7 +2047,6 @@ Fixed:
Example of threaded tables Example of threaded tables
```lua ```lua
package.path="?/init.lua;?.lua;"..package.path
local GLOBAL,sThread=require("multi.integration.lanesManager").init() local GLOBAL,sThread=require("multi.integration.lanesManager").init()
multi:newSystemThread("Test_Thread_1",function() multi:newSystemThread("Test_Thread_1",function()
require("multi") require("multi")
@@ -1912,7 +2372,6 @@ Added:</br>
Using multi:systemThreadedBenchmark() Using multi:systemThreadedBenchmark()
--- ---
```lua ```lua
package.path="?/init.lua;"..package.path
local GLOBAL,sThread=require("multi.integration.lanesManager").init() local GLOBAL,sThread=require("multi.integration.lanesManager").init()
multi:systemThreadedBenchmark(3):OnBench(function(self,count) multi:systemThreadedBenchmark(3):OnBench(function(self,count)
print("First Bench: "..count) print("First Bench: "..count)
@@ -1935,41 +2394,6 @@ GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2
-- Also, each thread has a .1 second delay! This is used to generate a random value for each thread! -- Also, each thread has a .1 second delay! This is used to generate a random value for each thread!
require("core.GuiManager") require("core.GuiManager")
gui.ff.Color=Color.Black gui.ff.Color=Color.Black
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
local c={}
c.name=name
if love then
if love.thread then
function c:init()
self.chan=love.thread.getChannel(self.name)
function self:push(v)
self.chan:push(v)
end
function self:pop()
return self.chan:pop()
end
GLOBAL[self.name]=self
return self
end
return c
else
error("Make sure you required the love.thread module!")
end
else
c.linda=lanes.linda()
function c:push(v)
self.linda:send("Q",v)
end
function c:pop()
return ({self.linda:receive(0,"Q")})[2]
end
function c:init()
return self
end
GLOBAL[name]=c
end
return c
end
queue=multi:newSystemThreadedQueue("QUEUE"):init() queue=multi:newSystemThreadedQueue("QUEUE"):init()
queue:push("This is a test") queue:push("This is a test")
queue:push("This is a test2") queue:push("This is a test2")
@@ -2251,7 +2675,7 @@ Change:
Upcomming: Upcomming:
--- ---
- Threaded objects wrapped in corutines, so you can hold/sleep without problems! - Threaded objects wrapped in coroutines, so you can hold/sleep without problems!
# Update: 1.4.0 (3/20/2017) # Update: 1.4.0 (3/20/2017)
Added: Added:
@@ -2325,8 +2749,10 @@ Added:
# Update: 1.2.0 (12.31.2016) # Update: 1.2.0 (12.31.2016)
Added: Added:
--- ---
- connectionobj.getConnection(name) — returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name) if you can orginize data before hand you can route info to certain connections thus saving a lot of cpu time. - connectionobj.getConnection(name) — returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name) if you can organize data before hand you can route info to certain connections thus saving a lot of cpu time.
**NOTE:** Only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used **NOTE:** Only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used
Changed: Changed:
--- ---
- Started keeping track of dates - Started keeping track of dates
@@ -2385,6 +2811,7 @@ Changed:
Changed: Changed:
--- ---
- Everything, complete restructuring of the library from function based to object based. Resembles the modern version of the library - Everything, complete restructuring of the library from function based to object based. Resembles the modern version of the library
Added: Added:
--- ---
- Love2d support basic - Love2d support basic
+2257
View File
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,9 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD if not (GLOBAL and THREAD) then
local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD
else
lanes = require("lanes")
end
function multi:newSystemThreadedQueue(name) function multi:newSystemThreadedQueue(name)
local name = name or multi.randomString(16)
local c = {} local c = {}
c.Name = name
c.linda = lanes.linda() c.linda = lanes.linda()
function c:push(v) function c:push(v)
self.linda:send("Q", v) self.linda:send("Q", v)
@@ -41,9 +47,12 @@ function multi:newSystemThreadedQueue(name)
GLOBAL[name or "_"] = c GLOBAL[name or "_"] = c
return c return c
end end
function multi:newSystemThreadedTable(name) function multi:newSystemThreadedTable(name)
local name = name or multi.randomString(16)
local c = {} local c = {}
c.link = lanes.linda() c.link = lanes.linda()
c.Name = name
setmetatable(c,{ setmetatable(c,{
__index = function(t,k) __index = function(t,k)
return c.link:get(k) return c.link:get(k)
@@ -58,14 +67,15 @@ function multi:newSystemThreadedTable(name)
GLOBAL[name or "_"] = c GLOBAL[name or "_"] = c
return c return c
end end
function multi:newSystemThreadedJobQueue(n) function multi:newSystemThreadedJobQueue(n)
local c = {} local c = {}
c.cores = n or THREAD.getCores()*2 c.cores = n or THREAD.getCores()*2
c.OnJobCompleted = multi:newConnection() c.OnJobCompleted = multi:newConnection()
local funcs = multi:newSystemThreadedTable() local funcs = multi:newSystemThreadedTable():init()
local queueJob = multi:newSystemThreadedQueue() local queueJob = multi:newSystemThreadedQueue():init()
local queueReturn = multi:newSystemThreadedQueue() local queueReturn = multi:newSystemThreadedQueue():init()
local doAll = multi:newSystemThreadedQueue() local doAll = multi:newSystemThreadedQueue():init()
local ID=1 local ID=1
local jid = 1 local jid = 1
function c:isEmpty() function c:isEmpty()
@@ -113,7 +123,7 @@ function multi:newSystemThreadedJobQueue(n)
end) end)
end,holup),name end,holup),name
end end
multi:newThread("JobQueueManager",function() thread:newThread("JobQueueManager",function()
while true do while true do
local job = thread.hold(function() local job = thread.hold(function()
return queueReturn:pop() return queueReturn:pop()
@@ -129,7 +139,7 @@ function multi:newSystemThreadedJobQueue(n)
local clock = os.clock local clock = os.clock
local ref = 0 local ref = 0
setmetatable(_G,{__index = funcs}) setmetatable(_G,{__index = funcs})
multi:newThread("JobHandler",function() thread:newThread("JobHandler",function()
while true do while true do
local dat = thread.hold(function() local dat = thread.hold(function()
return queueJob:pop() return queueJob:pop()
@@ -141,7 +151,7 @@ function multi:newSystemThreadedJobQueue(n)
queueReturn:push{jid, funcs[name](unpack(args)),queue} queueReturn:push{jid, funcs[name](unpack(args)),queue}
end end
end) end)
multi:newThread("DoAllHandler",function() thread:newThread("DoAllHandler",function()
while true do while true do
local dat = thread.hold(function() local dat = thread.hold(function()
return doAll:peek() return doAll:peek()
@@ -156,7 +166,7 @@ function multi:newSystemThreadedJobQueue(n)
end end
end end
end) end)
multi:newThread("IdleHandler",function() thread:newThread("IdleHandler",function()
while true do while true do
thread.hold(function() thread.hold(function()
return clock()-idle>3 return clock()-idle>3
@@ -168,4 +178,135 @@ function multi:newSystemThreadedJobQueue(n)
end,i).priority = thread.Priority_Core end,i).priority = thread.Priority_Core
end end
return c return c
end end
function multi:newSystemThreadedConnection(name)
local name = name or multi.randomString(16)
local c = {}
c.CONN = 0x00
c.TRIG = 0x01
c.PING = 0x02
c.PONG = 0x03
local function remove(a, b)
local ai = {}
local r = {}
for k,v in pairs(a) do ai[v]=true end
for k,v in pairs(b) do
if ai[v]==nil then table.insert(r,a[k]) end
end
return r
end
c.CID = THREAD.getID()
c.subscribe = multi:newSystemThreadedQueue("SUB_STC_"..self.Name):init()
c.Name = name
c.links = {} -- All triggers sent from main connection. When a connection is triggered on another thread, they speak to the main then send stuff out.
-- Locals will only live in the thread that creates the original object
local ping
local pong = function(link, links)
local res = thread.hold(function()
return link:peek()[1] == c.PONG
end,{sleep=3})
if not res then
for i=1,#links do
if links[i] == link then
table.remove(links,i,link)
break
end
end
else
link:pop()
end
end
ping = thread:newFunction(function(self)
ping:Pause()
multi.ForEach(self.links, function(link) -- Sync new connections
link:push{self.PING}
multi:newThread("pong Thread", pong, link, self.links)
end)
thread.sleep(3)
ping:Resume()
end,false)
local function fire(...)
for _, link in pairs(c.links) do
link:push {c.TRIG, {...}}
end
end
thread:newThread("STC_SUB_MAN"..name,function()
local item
local sub_func = function() -- This will keep things held up until there is something to process
return c.subscribe:pop()
end
while true do
thread.yield()
-- We need to check on broken connections
ping(c) -- Should return instantlly and process this in another thread
item = thread.hold(sub_func)
if item[1] == c.CONN then
multi.ForEach(c.links, function(link) -- Sync new connections
item[2]:push{c.CONN, link}
end)
c.links[#c.links+1] = item[2]
elseif item[1] == c.TRIG then
fire(unpack(item[2]))
c.proxy_conn:Fire(unpack(item[2]))
end
end
end)
--- ^^^ This will only exist in the init thread
function c:Fire(...)
local args = {...}
if self.CID == THREAD.getID() then -- Host Call
for _, link in pairs(self.links) do
link:push {self.TRIG, args}
end
self.proxy_conn:Fire(...)
else
self.subscribe:push {self.TRIG, args}
end
end
function c:init()
local multi, thread = require("multi"):init()
self.links = {}
self.proxy_conn = multi:newConnection()
local mt = getmetatable(self.proxy_conn)
setmetatable(self, {__index = self.proxy_conn, __call = function(t,func) self.proxy_conn(func) end, __add = mt.__add})
if self.CID == THREAD.getID() then return self end
thread:newThread("STC_CONN_MAN"..name,function()
local item
local link_self_ref = multi:newSystemThreadedQueue()
self.subscribe:push{self.CONN, link_self_ref}
while true do
item = thread.hold(function()
return link_self_ref:peek()
end)
if item[1] == self.PING then
link_self_ref:push{self.PONG}
link_self_ref:pop()
elseif item[1] == self.CONN then
if item[2].Name ~= link_self_ref.Name then
table.insert(self.links, item[2])
end
link_self_ref:pop()
elseif item[1] == self.TRIG then
self.proxy_conn:Fire(unpack(item[2]))
link_self_ref:pop()
else
-- This shouldn't be the case
end
end
end)
return self
end
GLOBAL[name] = c
return c
end
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -21,8 +21,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
package.path = "?/init.lua;?.lua;" .. package.path package.path = "?/init.lua;?.lua;" .. package.path
multi, thread = require("multi").init() -- get it all and have it on all lanes multi, thread = require("multi"):init() -- get it all and have it on all lanes
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassle if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassle
return { return {
init = function() init = function()
@@ -34,118 +35,140 @@ end
lanes = require("lanes").configure() lanes = require("lanes").configure()
multi.SystemThreads = {} multi.SystemThreads = {}
multi.isMainThread = true multi.isMainThread = true
function multi:canSystemThread() function multi:canSystemThread()
return true return true
end end
function multi:getPlatform() function multi:getPlatform()
return "lanes" return "lanes"
end end
-- Step 2 set up the Linda objects -- Step 2 set up the Linda objects
local __GlobalLinda = lanes.linda() -- handles global stuff local __GlobalLinda = lanes.linda() -- handles global stuff
local __SleepingLinda = lanes.linda() -- handles sleeping stuff local __SleepingLinda = lanes.linda() -- handles sleeping stuff
local __ConsoleLinda = lanes.linda() -- handles console stuff local __ConsoleLinda = lanes.linda() -- handles console stuff
multi:newLoop(function() local __StatusLinda = lanes.linda() -- handles pushstatus for stfunctions
local _,data = __ConsoleLinda:receive(0, "Q")
if data then local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda, __SleepingLinda, __StatusLinda, __ConsoleLinda)
print(unpack(data))
end
end)
local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
local threads = {}
local count = 1 local count = 1
local started = false local started = false
local livingThreads = {} local livingThreads = {}
function THREAD:newFunction(func,holup)
return function(...) function THREAD:newFunction(func,holdme)
local t = multi:newSystemThread("SystemThreadedFunction",function(...) return thread:newFunctionBase(function(...)
return func(...) return multi:newSystemThread("TempSystemThread",func,...)
end,...) end,holdme)()
return thread:newFunction(function()
thread.hold(function() return t.thread end)
return thread.hold(function()
return t.thread:join(.001)
end)
end,holup)()
end
end end
function multi:newSystemThread(name, func, ...) function multi:newSystemThread(name, func, ...)
local name = name or multi.randomString(16)
multi.InitSystemThreadErrorHandler() multi.InitSystemThreadErrorHandler()
rand = math.random(1, 10000000) local rand = math.random(1, 10000000)
local c = {} local return_linda = lanes.linda()
local __self = c c = {}
c.name = name c.name = name
c.Name = name c.Name = name
c.Id = count c.Id = count
c.loadString = {"base","package","os","io","math","table","string","coroutine"} c.loadString = {"base","package","os","io","math","table","string","coroutine"}
livingThreads[count] = {true, name} livingThreads[count] = {true, name}
c.returns = return_linda
c.Type = "sthread" c.Type = "sthread"
c.creationTime = os.clock() c.creationTime = os.clock()
c.alive = true c.alive = true
c.priority = THREAD.Priority_Normal c.priority = THREAD.Priority_Normal
local args = {...} local multi_settings = multi.defaultSettings
multi:newThread(function() for i,v in pairs(multi_settings) do
c.thread = lanes.gen(table.concat(c.loadString,","), print(i,v)
{ end
globals={ -- Set up some globals c.thread = lanes.gen("*",
THREAD_NAME=name, {
THREAD_ID=count, globals={ -- Set up some globals
THREAD = THREAD, THREAD_NAME = name,
GLOBAL = GLOBAL, THREAD_ID = count,
_Console = __ConsoleLinda THREAD = THREAD,
}, GLOBAL = GLOBAL,
priority=c.priority _Console = __ConsoleLinda
},func)(unpack(args)) },
thread.kill() priority=c.priority
end) },function(...)
require("multi"):init(multi_settings)
require("multi.integration.lanesManager.extensions")
local has_error = true
return_linda:set("returns",{func(...)})
has_error = false
end)(...)
count = count + 1 count = count + 1
function c:getName()
return c.Name
end
function c:kill() function c:kill()
self.thread:cancel() self.thread:cancel()
multi.print("Thread: '" .. self.name .. "' has been stopped!")
self.alive = false self.alive = false
end end
table.insert(multi.SystemThreads, c) table.insert(multi.SystemThreads, c)
c.OnDeath = multi:newConnection()
c.OnError = multi:newConnection() c.OnError = multi:newConnection()
GLOBAL["__THREADS__"] = livingThreads GLOBAL["__THREADS__"] = livingThreads
return c return c
end end
multi.OnSystemThreadDied = multi:newConnection()
THREAD.newSystemThread = multi.newSystemThread
function multi.InitSystemThreadErrorHandler() function multi.InitSystemThreadErrorHandler()
if started == true then if started == true then
return return
end end
started = true started = true
multi:newThread( thread:newThread("SystemThreadScheduler",function()
"ThreadErrorHandler", local threads = multi.SystemThreads
function() local _,data,status,push,temp
local threads = multi.SystemThreads while true do
while true do thread.yield()
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough. _,data = __ConsoleLinda:receive(0, "Q")
for i = #threads, 1, -1 do if data then print(unpack(data)) end
local v, err, t = threads[i].thread:join(.001) for i = #threads, 1, -1 do
if err then temp = threads[i]
if err:find("Thread was killed!") then status = temp.thread.status
print(err) push = __StatusLinda:get(temp.Id)
livingThreads[threads[i].Id] = {false, threads[i].Name} if push then
threads[i].alive = false temp.statusconnector:Fire(unpack(({__StatusLinda:receive(nil, temp.Id)})[2]))
multi.OnSystemThreadDied:Fire(threads[i].Id) end
GLOBAL["__THREADS__"] = livingThreads if status == "done" or temp.returns:get("returns") then
table.remove(threads, i) livingThreads[temp.Id] = {false, temp.Name}
elseif err:find("stack traceback") then temp.alive = false
print(err) temp.OnDeath:Fire(unpack(({temp.returns:receive(0, "returns")})[2]))
threads[i].OnError:Fire(threads[i], err, "Error in systemThread: '" .. threads[i].name .. "' <" .. err .. ">") GLOBAL["__THREADS__"] = livingThreads
threads[i].alive = false table.remove(threads, i)
livingThreads[threads[i].Id] = {false, threads[i].Name} elseif status == "running" then
multi.OnSystemThreadDied:Fire(threads[i].Id) --
GLOBAL["__THREADS__"] = livingThreads elseif status == "waiting" then
table.remove(threads, i) --
end elseif status == "error" then
end livingThreads[temp.Id] = {false, temp.Name}
temp.alive = false
temp.OnError:Fire(temp,unpack(temp.returns:receive(0,"returns") or {"Thread Killed!"}))
GLOBAL["__THREADS__"] = livingThreads
table.remove(threads, i)
elseif status == "cancelled" then
livingThreads[temp.Id] = {false, temp.Name}
temp.alive = false
temp.OnError:Fire(temp,"thread_cancelled")
GLOBAL["__THREADS__"] = livingThreads
table.remove(threads, i)
elseif status == "killed" then
livingThreads[temp.Id] = {false, temp.Name}
temp.alive = false
temp.OnError:Fire(temp,"thread_killed")
GLOBAL["__THREADS__"] = livingThreads
table.remove(threads, i)
end end
end end
end end
) end)
end end
print("Integrated Lanes!")
multi.print("Integrated Lanes!")
multi.integration = {} -- for module creators multi.integration = {} -- for module creators
multi.integration.GLOBAL = GLOBAL multi.integration.GLOBAL = GLOBAL
multi.integration.THREAD = THREAD multi.integration.THREAD = THREAD
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,8 @@ local function getOS()
return "unix" return "unix"
end end
end end
local function INIT(__GlobalLinda,__SleepingLinda)
local function INIT(__GlobalLinda, __SleepingLinda, __StatusLinda, __Console)
local THREAD = {} local THREAD = {}
THREAD.Priority_Core = 3 THREAD.Priority_Core = 3
THREAD.Priority_High = 2 THREAD.Priority_High = 2
@@ -37,12 +38,15 @@ local function INIT(__GlobalLinda,__SleepingLinda)
THREAD.Priority_Below_Normal = -1 THREAD.Priority_Below_Normal = -1
THREAD.Priority_Low = -2 THREAD.Priority_Low = -2
THREAD.Priority_Idle = -3 THREAD.Priority_Idle = -3
function THREAD.set(name, val) function THREAD.set(name, val)
__GlobalLinda:set(name, val) __GlobalLinda:set(name, val)
end end
function THREAD.get(name) function THREAD.get(name)
return __GlobalLinda:get(name) return __GlobalLinda:get(name)
end end
function THREAD.waitFor(name) function THREAD.waitFor(name)
local function wait() local function wait()
math.randomseed(os.time()) math.randomseed(os.time())
@@ -53,48 +57,64 @@ local function INIT(__GlobalLinda,__SleepingLinda)
until __GlobalLinda:get(name) until __GlobalLinda:get(name)
return __GlobalLinda:get(name) return __GlobalLinda:get(name)
end end
if getOS() == "windows" then if getOS() == "windows" then
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.getCores() function THREAD.getCores()
return THREAD.__CORES return THREAD.__CORES
end end
function THREAD.getConsole() function THREAD.getConsole()
local c = {} local c = {}
c.queue = _Console c.queue = __Console
function c.print(...) function c.print(...)
c.queue:send("Q", {...}) c.queue:send("Q", {...})
end end
function c.error(err) function c.error(err)
c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__} c.queue:push("Q",{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__})
error(err) error(err)
end end
return c return c
end end
function THREAD.getThreads() function THREAD.getThreads()
return GLOBAL.__THREADS__ return GLOBAL.__THREADS__
end end
if os.getOS() == "windows" then if os.getOS() == "windows" then
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.kill() -- trigger the lane destruction function THREAD.kill() -- trigger the lane destruction
error("Thread was killed!") error("Thread was killed!\1")
end end
function THREAD.getName() function THREAD.getName()
return THREAD_NAME return THREAD_NAME
end end
function THREAD.getID() function THREAD.getID()
return THREAD_ID return THREAD_ID
end end
function THREAD.pushStatus(...)
local args = {...}
__StatusLinda:send(nil,THREAD_ID, args)
end
_G.THREAD_ID = 0 _G.THREAD_ID = 0
function THREAD.sleep(n) function THREAD.sleep(n)
math.randomseed(os.time()) math.randomseed(os.time())
__SleepingLinda:receive(n, "__non_existing_variable") __SleepingLinda:receive(n, "__non_existing_variable")
end end
function THREAD.hold(n) function THREAD.hold(n)
local function wait() local function wait()
math.randomseed(os.time()) math.randomseed(os.time())
@@ -104,6 +124,7 @@ local function INIT(__GlobalLinda,__SleepingLinda)
wait() wait()
until n() until n()
end end
local GLOBAL = {} local GLOBAL = {}
setmetatable(GLOBAL, { setmetatable(GLOBAL, {
__index = function(t, k) __index = function(t, k)
@@ -115,6 +136,7 @@ local function INIT(__GlobalLinda,__SleepingLinda)
}) })
return GLOBAL, THREAD return GLOBAL, THREAD
end end
return {init = function(g,s)
return INIT(g,s) return {init = function(g,s,st,c)
return INIT(g,s,st,c)
end} end}
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
-- TODO make compatible with lovr if not ISTHREAD then
local multi, thread = require("multi").init() multi, thread = require("multi").init()
GLOBAL = multi.integration.GLOBAL GLOBAL = multi.integration.GLOBAL
THREAD = multi.integration.THREAD THREAD = multi.integration.THREAD
else
end
function multi:newSystemThreadedQueue(name) function multi:newSystemThreadedQueue(name)
local name = name or multi.randomString(16)
local c = {} local c = {}
c.Name = name c.Name = name
local fRef = {"func",nil} local fRef = {"func",nil}
@@ -64,10 +69,11 @@ function multi:newSystemThreadedQueue(name)
return c return c
end end
function multi:newSystemThreadedTable(name) function multi:newSystemThreadedTable(name)
local name = name or multi.randomString(16)
local c = {} local c = {}
c.name = name c.Name = name
function c:init() function c:init()
return THREAD.createTable(self.name) return THREAD.createTable(self.Name)
end end
THREAD.package(name,c) THREAD.package(name,c)
return c return c
@@ -131,7 +137,7 @@ function multi:newSystemThreadedJobQueue(n)
end) end)
end,holup),name end,holup),name
end end
multi:newThread("jobManager",function() thread:newThread("jobManager",function()
while true do while true do
thread.yield() thread.yield()
local dat = c.queueReturn:pop() local dat = c.queueReturn:pop()
@@ -155,7 +161,7 @@ function multi:newSystemThreadedJobQueue(n)
local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
local registry = {} local registry = {}
setmetatable(_G,{__index = funcs}) setmetatable(_G,{__index = funcs})
multi:newThread("startUp",function() thread:newThread("startUp",function()
while true do while true do
thread.yield() thread.yield()
local all = queueAll:peek() local all = queueAll:peek()
@@ -165,7 +171,7 @@ function multi:newSystemThreadedJobQueue(n)
end end
end end
end) end)
multi:newThread("runner",function() thread:newThread("runner",function()
thread.sleep(.1) thread.sleep(.1)
while true do while true do
thread.yield() thread.yield()
@@ -187,7 +193,7 @@ function multi:newSystemThreadedJobQueue(n)
end):OnError(function(...) end):OnError(function(...)
error(...) error(...)
end) end)
multi:newThread("Idler",function() thread:newThread("Idler",function()
while true do while true do
thread.yield() thread.yield()
if clock()-lastProc> 2 then if clock()-lastProc> 2 then
@@ -201,5 +207,143 @@ function multi:newSystemThreadedJobQueue(n)
end,jqc) end,jqc)
end end
jqc = jqc + 1 jqc = jqc + 1
return c
end
function multi:newSystemThreadedConnection(name)
local name = name or multi.randomString(16)
local c = {}
c.CONN = 0x00
c.TRIG = 0x01
c.PING = 0x02
c.PONG = 0x03
local subscribe = multi:newSystemThreadedQueue("SUB_STC_" .. name):init()
function c:init()
self.subscribe = THREAD.waitFor("SUB_STC_" .. self.Name):init()
function self:Fire(...)
local args = {...}
if self.CID == THREAD.getID() then -- Host Call
for _, link in pairs(self.links) do
link:push{self.TRIG, args}
end
self.proxy_conn:Fire(...)
else
self.subscribe:push{self.TRIG, args}
end
end
local multi, thread = require("multi"):init()
self.links = {}
self.proxy_conn = multi:newConnection()
local mt = getmetatable(self.proxy_conn)
setmetatable(self, {__index = self.proxy_conn, __call = function(t,func) self.proxy_conn(func) end, __add = mt.__add})
if self.CID == THREAD.getID() then return self end
thread:newThread("STC_CONN_MAN" .. self.Name,function()
local item
local string_self_ref = "LSF_" .. multi.randomString(16)
local link_self_ref = multi:newSystemThreadedQueue():init()
self.subscribe:push{self.CONN, string_self_ref}
while true do
item = thread.hold(function()
return link_self_ref:peek()
end)
if item[1] == self.PING then
link_self_ref:push{self.PONG}
link_self_ref:pop()
elseif item[1] == self.CONN then
if string_self_ref ~= item[2] then
table.insert(self.links, THREAD.waitFor(item[2]):init())
end
link_self_ref:pop()
elseif item[1] == self.TRIG then
self.proxy_conn:Fire(unpack(item[2]))
link_self_ref:pop()
else
-- This shouldn't be the case
end
end
end).OnError(print)
return self
end
local function remove(a, b)
local ai = {}
local r = {}
for k,v in pairs(a) do ai[v]=true end
for k,v in pairs(b) do
if ai[v]==nil then table.insert(r,a[k]) end
end
return r
end
c.CID = THREAD.getID()
c.Name = name
c.links = {} -- All triggers sent from main connection. When a connection is triggered on another thread, they speak to the main then send stuff out.
-- Locals will only live in the thread that creates the original object
local ping
local pong = function(link, links)
local res = thread.hold(function()
return link:peek()[1] == c.PONG
end,{sleep=3})
if not res then
for i=1,#links do
if links[i] == link then
table.remove(links,i,link)
break
end
end
else
link:pop()
end
end
ping = thread:newFunction(function(self)
ping:Pause()
multi.ForEach(self.links, function(link) -- Sync new connections
link:push{self.PING}
multi:newThread("pong Thread", pong, link, links)
end)
thread.sleep(3)
ping:Resume()
end,false)
local function fire(...)
for _, link in pairs(c.links) do
link:push {c.TRIG, {...}}
end
end
thread:newThread("STC_SUB_MAN"..name,function()
local item
while true do
thread.yield()
-- We need to check on broken connections
ping(c) -- Should return instantlly and process this in another thread
item = thread.hold(function() -- This will keep things held up until there is something to process
return c.subscribe:pop()
end)
if item[1] == c.CONN then
multi.ForEach(c.links, function(link) -- Sync new connections
THREAD.waitFor(item[2]):init():push{c.CONN, link.Name}
end)
print("Adding link")
c.links[#c.links+1] = THREAD.waitFor(item[2]):init()
elseif item[1] == c.TRIG then
fire(unpack(item[2]))
c.proxy_conn:Fire(unpack(item[2]))
end
end
end).OnError(print)
--- ^^^ This will only exist in the init thread
THREAD.package(name,c)
return c return c
end end
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -35,9 +35,10 @@ __THREADNAME__=table.remove(__IMPORTS,1)
stab = THREAD.createStaticTable(__THREADNAME__) stab = THREAD.createStaticTable(__THREADNAME__)
GLOBAL = THREAD.getGlobal() GLOBAL = THREAD.getGlobal()
multi, thread = require("multi").init() multi, thread = require("multi").init()
print(pcall(require,"multi.integration.loveManager.extensions"))
stab["returns"] = {THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))} stab["returns"] = {THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))}
]] ]]
local multi, thread = require("multi.compat.love2d"):init() local multi, thread = require("multi"):init()
local THREAD = {} local THREAD = {}
__THREADID__ = 0 __THREADID__ = 0
__THREADNAME__ = "MainThread" __THREADNAME__ = "MainThread"
@@ -48,21 +49,7 @@ local GLOBAL = THREAD.getGlobal()
local THREAD_ID = 1 local THREAD_ID = 1
local OBJECT_ID = 0 local OBJECT_ID = 0
local stf = 0 local stf = 0
function THREAD:newFunction(func,holup)
stf = stf + 1
return function(...)
local t = multi:newSystemThread("STF"..stf,func,...)
return thread:newFunction(function()
return thread.hold(function()
if t.stab["returns"] then
local dat = t.stab.returns
t.stab.returns = nil
return unpack(dat)
end
end)
end,holup)()
end
end
function multi:newSystemThread(name,func,...) function multi:newSystemThread(name,func,...)
local c = {} local c = {}
c.name = name c.name = name
@@ -70,18 +57,60 @@ function multi:newSystemThread(name,func,...)
c.thread=love.thread.newThread(ThreadFileData) c.thread=love.thread.newThread(ThreadFileData)
c.thread:start(THREAD.dump(func),c.ID,c.name,...) c.thread:start(THREAD.dump(func),c.ID,c.name,...)
c.stab = THREAD.createStaticTable(name) c.stab = THREAD.createStaticTable(name)
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread} c.OnDeath = multi:newConnection()
c.OnError = multi:newConnection()
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID, Name=c.name, Thread=c.thread}
GLOBAL["__THREAD_COUNT"] = THREAD_ID GLOBAL["__THREAD_COUNT"] = THREAD_ID
THREAD_ID=THREAD_ID+1 THREAD_ID=THREAD_ID + 1
function c:getName()
return c.name
end
thread:newThread(function()
if name:find("TempSystemThread") then
local status_channel = love.thread.getChannel("__"..c.ID.."__MULTI__STATUS_CHANNEL__")
thread.hold(function()
-- While the thread is running we might as well do something in the loop
local status = status_channel
if status:peek()~=nil then
c.statusconnector:Fire(unpack(status:pop()))
end
return not c.thread:isRunning()
end)
else
thread.hold(function()
return not c.thread:isRunning()
end)
end
-- If the thread is not running let's handle that.
local thread_err = c.thread:getError()
if thread_err == "Thread Killed!\1" then
c.OnDeath:Fire("Thread Killed!")
elseif thread_err then
c.OnError:Fire(c,thread_err)
elseif c.stab.returns then
c.OnDeath:Fire(unpack(c.stab.returns))
c.stab.returns = nil
end
end)
return c return c
end end
function love.threaderror(thread, errorstr)
print("Thread error!\n"..errorstr) function THREAD:newFunction(func)
return thread:newFunctionBase(function(...)
return multi:newSystemThread("TempSystemThread"..THREAD_ID,func,...)
end)()
end end
THREAD.newSystemThread = multi.newSystemThread
function love.threaderror(thread, errorstr)
multi.print("Thread error!\n"..errorstr)
end
multi.integration.GLOBAL = GLOBAL multi.integration.GLOBAL = GLOBAL
multi.integration.THREAD = THREAD multi.integration.THREAD = THREAD
require("multi.integration.loveManager.extensions") require("multi.integration.loveManager.extensions")
print("Integrated Love Threading!") multi.print("Integrated Love Threading!")
return {init=function() return {init=function()
return GLOBAL,THREAD return GLOBAL,THREAD
end} end}
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -24,15 +24,19 @@ SOFTWARE.
require("love.timer") require("love.timer")
require("love.system") require("love.system")
require("love.data") require("love.data")
require("love.thread")
local socket = require("socket") local socket = require("socket")
local multi, thread = require("multi").init() local multi, thread = require("multi").init()
local threads = {} local threads = {}
function threads.loadDump(d) function threads.loadDump(d)
return loadstring(d:getString()) return loadstring(d:getString())
end end
function threads.dump(func) function threads.dump(func)
return love.data.newByteData(string.dump(func)) return love.data.newByteData(string.dump(func))
end end
local fRef = {"func",nil} local fRef = {"func",nil}
local function manage(channel, value) local function manage(channel, value)
channel:clear() channel:clear()
@@ -44,6 +48,7 @@ local function manage(channel, value)
channel:push(value) channel:push(value)
end end
end end
local function RandomVariable(length) local function RandomVariable(length)
local res = {} local res = {}
math.randomseed(socket.gettime()*10000) math.randomseed(socket.gettime()*10000)
@@ -52,12 +57,14 @@ local function RandomVariable(length)
end end
return table.concat(res) return table.concat(res)
end end
local GNAME = "__GLOBAL_" local GNAME = "__GLOBAL_"
local proxy = {} local proxy = {}
function threads.set(name,val) function threads.set(name,val)
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
proxy[name]:performAtomic(manage, val) proxy[name]:performAtomic(manage, val)
end end
function threads.get(name) function threads.get(name)
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
local dat = proxy[name]:peek() local dat = proxy[name]:peek()
@@ -67,6 +74,7 @@ function threads.get(name)
return dat return dat
end end
end end
function threads.waitFor(name) function threads.waitFor(name)
if thread.isThread() then if thread.isThread() then
return thread.hold(function() return thread.hold(function()
@@ -82,18 +90,28 @@ function threads.waitFor(name)
end end
return dat return dat
end end
function threads.package(name,val) function threads.package(name,val)
local init = val.init local init = val.init
val.init=threads.dump(val.init) val.init=threads.dump(val.init)
GLOBAL[name]=val GLOBAL[name]=val
val.init=init val.init=init
end end
function threads.getCores() function threads.getCores()
return love.system.getProcessorCount() return love.system.getProcessorCount()
end end
function threads.kill() function threads.kill()
error("Thread Killed!") error("Thread Killed!\1")
end end
function threads.pushStatus(...)
local status_channel = love.thread.getChannel("__"..__THREADID__.."__MULTI__STATUS_CHANNEL__")
local args = {...}
status_channel:push(__THREADID__, args)
end
function threads.getThreads() function threads.getThreads()
local t = {} local t = {}
for i=1,GLOBAL["__THREAD_COUNT"] do for i=1,GLOBAL["__THREAD_COUNT"] do
@@ -101,18 +119,23 @@ function threads.getThreads()
end end
return t return t
end end
function threads.getThread(n) function threads.getThread(n)
return GLOBAL["__THREAD_"..n] return GLOBAL["__THREAD_"..n]
end end
function threads.getName() function threads.getName()
return __THREADNAME__ return __THREADNAME__
end end
function threads.getID() function threads.getID()
return __THREADID__ return __THREADID__
end end
function threads.sleep(n) function threads.sleep(n)
love.timer.sleep(n) love.timer.sleep(n)
end end
function threads.getGlobal() function threads.getGlobal()
return setmetatable({}, return setmetatable({},
{ {
@@ -125,6 +148,7 @@ function threads.getGlobal()
} }
) )
end end
function threads.createTable(n) function threads.createTable(n)
local _proxy = {} local _proxy = {}
local function set(name,val) local function set(name,val)
@@ -151,6 +175,7 @@ function threads.createTable(n)
} }
) )
end end
function threads.getConsole() function threads.getConsole()
local c = {} local c = {}
c.queue = love.thread.getChannel("__CONSOLE__") c.queue = love.thread.getChannel("__CONSOLE__")
@@ -163,11 +188,12 @@ function threads.getConsole()
end end
return c return c
end end
if not ISTHREAD then if not ISTHREAD then
local clock = os.clock local clock = os.clock
local lastproc = clock() local lastproc = clock()
local queue = love.thread.getChannel("__CONSOLE__") local queue = love.thread.getChannel("__CONSOLE__")
multi:newThread("consoleManager",function() thread:newThread("consoleManager",function()
while true do while true do
thread.yield() thread.yield()
dat = queue:pop() dat = queue:pop()
@@ -181,6 +207,7 @@ if not ISTHREAD then
end end
end) end)
end end
function threads.createStaticTable(n) function threads.createStaticTable(n)
local __proxy = {} local __proxy = {}
local function set(name,val) local function set(name,val)
@@ -212,10 +239,12 @@ function threads.createStaticTable(n)
} }
) )
end end
function threads.hold(n) function threads.hold(n)
local dat local dat
while not(dat) do while not(dat) do
dat = n() dat = n()
end end
end end
return threads return threads
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -129,7 +129,7 @@ function multi:newSystemThreadedJobQueue(n)
end) end)
end,holup),name end,holup),name
end end
multi:newThread("jobManager",function() thread:newThread("jobManager",function()
while true do while true do
thread.yield() thread.yield()
local dat = c.queueReturn:pop() local dat = c.queueReturn:pop()
@@ -153,7 +153,7 @@ function multi:newSystemThreadedJobQueue(n)
local queueAll = lovr.thread.getChannel("__JobQueue_"..jqc.."_queueAll") local queueAll = lovr.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
local registry = {} local registry = {}
setmetatable(_G,{__index = funcs}) setmetatable(_G,{__index = funcs})
multi:newThread("startUp",function() thread:newThread("startUp",function()
while true do while true do
thread.yield() thread.yield()
local all = queueAll:peek() local all = queueAll:peek()
@@ -163,7 +163,7 @@ function multi:newSystemThreadedJobQueue(n)
end end
end end
end) end)
multi:newThread("runner",function() thread:newThread("runner",function()
thread.sleep(.1) thread.sleep(.1)
while true do while true do
thread.yield() thread.yield()
@@ -185,7 +185,7 @@ function multi:newSystemThreadedJobQueue(n)
end):OnError(function(...) end):OnError(function(...)
error(...) error(...)
end) end)
multi:newThread("Idler",function() thread:newThread("Idler",function()
while true do while true do
thread.yield() thread.yield()
if clock()-lastProc> 2 then if clock()-lastProc> 2 then
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -76,6 +76,7 @@ function multi:newSystemThread(name,func,...)
THREAD_ID=THREAD_ID+1 THREAD_ID=THREAD_ID+1
return c return c
end end
THREAD.newSystemThread = multi.newSystemThread
function lovr.threaderror(thread, errorstr) function lovr.threaderror(thread, errorstr)
print("Thread error!\n"..errorstr) print("Thread error!\n"..errorstr)
end end
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -168,7 +168,7 @@ if not ISTHREAD then
local clock = os.clock local clock = os.clock
local lastproc = clock() local lastproc = clock()
local queue = lovr.thread.getChannel("__CONSOLE__") local queue = lovr.thread.getChannel("__CONSOLE__")
multi:newThread("consoleManager",function() thread:newThread("consoleManager",function()
while true do while true do
thread.yield() thread.yield()
dat = queue:pop() dat = queue:pop()
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -116,6 +116,7 @@ local function _INIT(luvitThread, timer)
luvitThread.start(entry, package.path, name, c.func, ...) luvitThread.start(entry, package.path, name, c.func, ...)
return c return c
end end
THREAD.newSystemThread = multi.newSystemThread
multi.print("Integrated Luvit!") multi.print("Integrated Luvit!")
multi.integration = {} -- for module creators multi.integration = {} -- for module creators
multi.integration.GLOBAL = GLOBAL multi.integration.GLOBAL = GLOBAL
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@ SOFTWARE.
]] ]]
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
local net = require("net") local net = require("net")
local bin = require("bin") --local bin = require("bin")
local char = string.char local char = string.char
local byte = string.byte local byte = string.byte
bin.setBitsInterface(infinabits) bin.setBitsInterface(infinabits)
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -72,7 +72,7 @@ function master:newNetworkThread(nodeName,func,...)
local ret local ret
local nID = netID local nID = netID
local conn = multi:newConnection() local conn = multi:newConnection()
multi:newThread(function() thread:newthread(function()
dat:addBlock{ dat:addBlock{
args = args, args = args,
func = func, func = func,
@@ -143,7 +143,7 @@ function multi:newMasterNode(cd)
else else
c:getNodesFromBroadcast() c:getNodesFromBroadcast()
end end
multi:newThread("CMDQueueProcessor",function() thread:newthread("CMDQueueProcessor",function()
while true do while true do
thread.skip(128) thread.skip(128)
local data = table.remove(c._queue,1) local data = table.remove(c._queue,1)
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -125,7 +125,7 @@ function multi:newSystemThreadedJobQueue(n)
end,holup),name end,holup),name
end end
for i=1,c.cores do for i=1,c.cores do
multi:newThread("PesudoThreadedJobQueue_"..i,function() thread:newthread("PesudoThreadedJobQueue_"..i,function()
while true do while true do
thread.yield() thread.yield()
if #jobs>0 then if #jobs>0 then
@@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
package.path = "?/init.lua;?.lua;" .. package.path package.path = "?/init.lua;?.lua;" .. package.path
local multi, thread = require("multi").init() local multi, thread = require("multi"):init()
if multi.integration then if multi.integration then
return { return {
@@ -32,7 +32,7 @@ if multi.integration then
} }
end end
local GLOBAL, THREAD = require("multi.integration.pesudoManager.threads"):init() local GLOBAL, THREAD = require("multi.integration.pesudoManager.threads").init(thread)
function multi:canSystemThread() -- We are emulating system threading function multi:canSystemThread() -- We are emulating system threading
return true return true
@@ -41,6 +41,7 @@ end
function multi:getPlatform() function multi:getPlatform()
return "pesudo" return "pesudo"
end end
local function split(str) local function split(str)
local tab = {} local tab = {}
for word in string.gmatch(str, '([^,]+)') do for word in string.gmatch(str, '([^,]+)') do
@@ -48,13 +49,16 @@ local function split(str)
end end
return tab return tab
end end
THREAD.newFunction=thread.newFunction
local tab = [[_VERSION,io,os,require,load,debug,assert,collectgarbage,error,getfenv,getmetatable,ipairs,loadstring,module,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,xpcall,math,coroutine,string,table]]
tab = split(tab)
local id = 0 local id = 0
function multi:newSystemThread(name,func,...) function multi:newSystemThread(name,func,...)
GLOBAL["$THREAD_NAME"] = name GLOBAL["$THREAD_NAME"] = name
GLOBAL["$__THREADNAME__"] = name GLOBAL["$__THREADNAME__"] = name
GLOBAL["$THREAD_ID"] = id GLOBAL["$THREAD_ID"] = id
--GLOBAL["$thread"] = thread GLOBAL["$thread"] = thread
local env = { local env = {
GLOBAL = GLOBAL, GLOBAL = GLOBAL,
THREAD = THREAD, THREAD = THREAD,
@@ -64,21 +68,28 @@ function multi:newSystemThread(name,func,...)
thread = thread thread = thread
} }
local tab = [[_VERSION,io,os,require,load,debug,assert,collectgarbage,error,getfenv,getmetatable,ipairs,loadstring,module,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,xpcall,math,coroutine,string,table]]
tab = split(tab)
for i = 1,#tab do for i = 1,#tab do
env[tab[i]] = _G[tab[i]] env[tab[i]] = _G[tab[i]]
end end
--setmetatable(env,{__index=env})
multi:newISOThread(name,func,env,...).OnError(function(self,msg) local th = thread:newISOThread(name,func,env,...)
print("ERROR:",msg)
end)
id = id + 1 id = id + 1
return th
end end
THREAD.newSystemThread = multi.newSystemThread
-- System threads as implemented here cannot share memory, but use a message passing system. -- System threads as implemented here cannot share memory, but use a message passing system.
-- An isolated thread allows us to mimic that behavior so if access data from the "main" thread happens things will not work. This behavior is in line with how the system threading works -- An isolated thread allows us to mimic that behavior so if access data from the "main" thread happens things will not work. This behavior is in line with how the system threading works
print("Integrated Pesudo Threading!") function THREAD:newFunction(func,holdme)
return thread:newFunctionBase(function(...)
return multi:newSystemThread("TempSystemThread",func,...)
end,holdme)()
end
multi.print("Integrated Pesudo Threading!")
multi.integration = {} -- for module creators multi.integration = {} -- for module creators
multi.integration.GLOBAL = GLOBAL multi.integration.GLOBAL = GLOBAL
multi.integration.THREAD = THREAD multi.integration.THREAD = THREAD
@@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2020 Ryan Ward Copyright (c) 2022 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local function getOS() local function getOS()
if package.config:sub(1, 1) == "\\" then if package.config:sub(1, 1) == "\\" then
return "windows" return "windows"
@@ -28,7 +29,8 @@ local function getOS()
return "unix" return "unix"
end end
end end
local function INIT(env)
local function INIT(thread)
local THREAD = {} local THREAD = {}
local GLOBAL = {} local GLOBAL = {}
THREAD.Priority_Core = 3 THREAD.Priority_Core = 3
@@ -38,24 +40,29 @@ local function INIT(env)
THREAD.Priority_Below_Normal = -1 THREAD.Priority_Below_Normal = -1
THREAD.Priority_Low = -2 THREAD.Priority_Low = -2
THREAD.Priority_Idle = -3 THREAD.Priority_Idle = -3
function THREAD.set(name, val) function THREAD.set(name, val)
GLOBAL[name] = val GLOBAL[name] = val
end end
function THREAD.get(name) function THREAD.get(name)
return GLOBAL[name] return GLOBAL[name]
end end
function THREAD.waitFor(name) function THREAD.waitFor(name)
print("Waiting",thread)
return thread.hold(function() return GLOBAL[name] end) return thread.hold(function() return GLOBAL[name] end)
end end
if getOS() == "windows" then if getOS() == "windows" then
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.getCores() function THREAD.getCores()
return THREAD.__CORES return THREAD.__CORES
end end
function THREAD.getConsole() function THREAD.getConsole()
local c = {} local c = {}
function c.print(...) function c.print(...)
@@ -66,31 +73,38 @@ local function INIT(env)
end end
return c return c
end end
function THREAD.getThreads() function THREAD.getThreads()
return {}--GLOBAL.__THREADS__ return {}--GLOBAL.__THREADS__
end end
THREAD.pushStatus = thread.pushStatus
if os.getOS() == "windows" then if os.getOS() == "windows" then
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.kill() function THREAD.kill()
error("Thread was killed!") error("Thread was killed!")
end end
function THREAD.getName() function THREAD.getName()
return GLOBAL["$THREAD_NAME"] return GLOBAL["$THREAD_NAME"]
end end
function THREAD.getID() function THREAD.getID()
return GLOBAL["$THREAD_ID"] return GLOBAL["$THREAD_ID"]
end end
function THREAD.sleep(n)
thread.sleep(n) THREAD.sleep = thread.sleep
end
function THREAD.hold(n) THREAD.hold = thread.hold
return thread.hold(n)
end
return GLOBAL, THREAD return GLOBAL, THREAD
end end
return {init = function()
return INIT() return {init = function(thread)
return INIT(thread)
end} end}
-273
View File
@@ -1,273 +0,0 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
if table.unpack then
unpack=table.unpack
end
function table.val_to_str ( v )
if "string" == type( v ) then
v = string.gsub( v, "\n", "\\n" )
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
return "'" .. v .. "'"
end
return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
else
return "table" == type( v ) and table.tostring( v ) or
tostring( v )
end
end
function table.key_to_str ( k )
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
return k
else
return "[" .. table.val_to_str( k ) .. "]"
end
end
function table.tostring( tbl )
local result, done = {}, {}
for k, v in ipairs( tbl ) do
table.insert( result, table.val_to_str( v ) )
done[ k ] = true
end
for k, v in pairs( tbl ) do
if not done[ k ] then
table.insert( result,
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
end
end
return "{" .. table.concat( result, "," ) .. "}"
end
function table.merge(t1, t2)
t1,t2= t1 or {},t2 or {}
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
table.merge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
Library={}
function Library.inject(lib,dat,arg)
if type(lib)=="table" then
if type(dat)=="table" then
table.merge(lib,dat)
elseif type(dat)=="string" then
if lib.Version and dat:match("(%d-)%.(%d-)%.(%d-)") then
lib.Version={dat:match("(%d+)%.(%d+)%.(%d+)")}
elseif dat=="meta" and type(arg)=="table" then
local _mt=getmetatable(lib) or {}
local mt={}
table.merge(mt,arg)
table.merge(_mt,mt)
setmetatable(lib,_mt)
elseif dat=="compat" then
lib["getVersion"]=function(self) return self.Version[1].."."..self.Version[2].."."..self.Version[3] end
if not lib.Version then
lib.Version={1,0,0}
end
elseif dat=="inhert" then
if not(lib["!%"..arg.."%!"]) then print("Wrong Password!!") return end
lib["!%"..arg.."%!"].__index=lib["!!%"..arg.."%!!"]
end
elseif type(dat)=="function" then
for i,v in pairs(lib) do
dat(lib,i,v)
end
end
elseif type(lib)=="function" or type(lib)=="userdata" then
if lib==unpack then
print("function unpack cannot yet be injected!")
return unpack
elseif lib==pairs then
print("function pairs cannot yet be injected!")
return lib
elseif lib==ipairs then
print("function ipairs cannot yet be injected!")
return lib
elseif lib==type then
print("function type cannot yet be injected!")
return lib
end
temp={}
local mt={
__call=function(t,...)
local consume,MainRet,init={},{},{...}
local tt={}
for i=1,#t.__Link do
tt={}
if t.__Link[i]==t.__Main then
if #consume~=0 then
MainRet={t.__Link[i](unpack(consume))}
else
MainRet={t.__Link[i](unpack(init))}
end
else
if i==1 then
consume=(t.__Link[i](unpack(init)))
else
if type(MainRet)=="table" then
table.merge(tt,MainRet)
end
if type(consume)=="table" then
table.merge(tt,consume)
end
consume={t.__Link[i](unpack(tt))}
end
if i==#t.__Link then
return unpack(consume)
end
if consume then if consume[0]=="\1\7\6\3\2\99\125" then consume[0]=nil return unpack(consume) end end
end
end
if type(MainRet)=="table" then
table.merge(tt,MainRet)
end
if type(consume)=="table" then
table.merge(tt,consume)
end
return unpack(tt)
end,
}
temp.__Link={lib}
temp.__Main=lib
temp.__self=temp
function temp:inject(func,i)
if i then
table.insert(self.__Link,i,func)
else
table.insert(self.__Link,func)
end
end
function temp:consume(func)
for i=1,#self.__Link do
if self.__Link[i]==self.__Main then
self.__Link[i]=func
self.__self.__Main=func
return true
end
end
return false
end
setmetatable(temp,mt)
return temp
else
return "arg1 must be a table or a function"
end
end
function Library.convert(...)
local temp,rets={...},{}
for i=1,#temp do
if type(temp[i])=="function" then
table.insert(rets,Library.inject(temp[i]))
else
error("Takes only functions and returns in order from functions given. arg # "..i.." is not a function!!! It is a "..type(temp[i]))
end
end
return unpack(rets)
end
local link={MainLibrary=Library}
Library.inject(Library,"meta",{
__Link=link,
__call=function(self,func) func(link) end,
})
local multi, thread = require("multi").init()
os.sleep = love.timer.sleep
multi.drawF = {}
function multi:onDraw(func, i)
i = i or 1
table.insert(self.drawF, i, func)
end
multi.OnKeyPressed = multi:newConnection()
multi.OnKeyReleased = multi:newConnection()
multi.OnMousePressed = multi:newConnection()
multi.OnMouseReleased = multi:newConnection()
multi.OnMouseWheelMoved = multi:newConnection()
multi.OnMouseMoved = multi:newConnection()
multi.OnDraw = multi:newConnection()
multi.OnTextInput = multi:newConnection()
multi.OnUpdate = multi:newConnection()
multi.OnQuit = multi:newConnection()
multi.OnPreLoad(function()
local function Hook(func, conn)
if love[func] ~= nil then
love[func] = Library.convert(love[func])
love[func]:inject(function(...)
conn:Fire(...)
return {...}
end,1)
elseif love[func] == nil then
love[func] = function(...)
conn:Fire(...)
end
end
end
Hook("quit", multi.OnQuit)
Hook("keypressed", multi.OnKeyPressed)
Hook("keyreleased", multi.OnKeyReleased)
Hook("mousepressed", multi.OnMousePressed)
Hook("mousereleased", multi.OnMouseReleased)
Hook("wheelmoved", multi.OnMouseWheelMoved)
Hook("mousemoved", multi.OnMouseMoved)
Hook("draw", multi.OnDraw)
Hook("textinput", multi.OnTextInput)
Hook("update", multi.OnUpdate)
multi.OnDraw(function()
for i = 1, #multi.drawF do
love.graphics.setColor(255, 255, 255, 255)
multi.drawF[i]()
end
end)
end)
function multi:loveloop(light)
local link
link = multi:newThread(function()
local mainloop = love.run()
while true do
thread.yield()
pcall(mainloop)
end
end).OnError(function(...)
print(...)
end)
if light==false then
multi:mainloop()
else
multi:lightloop()
end
end
multi.OnQuit(function()
multi.Stop()
love.event.quit()
end)
return multi
-281
View File
@@ -1,281 +0,0 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
if table.unpack then
unpack=table.unpack
end
function table.val_to_str ( v )
if "string" == type( v ) then
v = string.gsub( v, "\n", "\\n" )
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
return "'" .. v .. "'"
end
return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
else
return "table" == type( v ) and table.tostring( v ) or
tostring( v )
end
end
function table.key_to_str ( k )
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
return k
else
return "[" .. table.val_to_str( k ) .. "]"
end
end
function table.tostring( tbl )
local result, done = {}, {}
for k, v in ipairs( tbl ) do
table.insert( result, table.val_to_str( v ) )
done[ k ] = true
end
for k, v in pairs( tbl ) do
if not done[ k ] then
table.insert( result,
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
end
end
return "{" .. table.concat( result, "," ) .. "}"
end
function table.merge(t1, t2)
t1,t2= t1 or {},t2 or {}
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
table.merge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
Library={}
function Library.inject(lib,dat,arg)
if type(lib)=="table" then
if type(dat)=="table" then
table.merge(lib,dat)
elseif type(dat)=="string" then
if lib.Version and dat:match("(%d-)%.(%d-)%.(%d-)") then
lib.Version={dat:match("(%d+)%.(%d+)%.(%d+)")}
elseif dat=="meta" and type(arg)=="table" then
local _mt=getmetatable(lib) or {}
local mt={}
table.merge(mt,arg)
table.merge(_mt,mt)
setmetatable(lib,_mt)
elseif dat=="compat" then
lib["getVersion"]=function(self) return self.Version[1].."."..self.Version[2].."."..self.Version[3] end
if not lib.Version then
lib.Version={1,0,0}
end
elseif dat=="inhert" then
if not(lib["!%"..arg.."%!"]) then print("Wrong Password!!") return end
lib["!%"..arg.."%!"].__index=lib["!!%"..arg.."%!!"]
end
elseif type(dat)=="function" then
for i,v in pairs(lib) do
dat(lib,i,v)
end
end
elseif type(lib)=="function" or type(lib)=="userdata" then
if lib==unpack then
print("function unpack cannot yet be injected!")
return unpack
elseif lib==pairs then
print("function pairs cannot yet be injected!")
return lib
elseif lib==ipairs then
print("function ipairs cannot yet be injected!")
return lib
elseif lib==type then
print("function type cannot yet be injected!")
return lib
end
temp={}
local mt={
__call=function(t,...)
local consume,MainRet,init={},{},{...}
local tt={}
for i=1,#t.__Link do
tt={}
if t.__Link[i]==t.__Main then
if #consume~=0 then
MainRet={t.__Link[i](unpack(consume))}
else
MainRet={t.__Link[i](unpack(init))}
end
else
if i==1 then
consume=(t.__Link[i](unpack(init)))
else
if type(MainRet)=="table" then
table.merge(tt,MainRet)
end
if type(consume)=="table" then
table.merge(tt,consume)
end
consume={t.__Link[i](unpack(tt))}
end
if i==#t.__Link then
return unpack(consume)
end
if consume then if consume[0]=="\1\7\6\3\2\99\125" then consume[0]=nil return unpack(consume) end end
end
end
if type(MainRet)=="table" then
table.merge(tt,MainRet)
end
if type(consume)=="table" then
table.merge(tt,consume)
end
return unpack(tt)
end,
}
temp.__Link={lib}
temp.__Main=lib
temp.__self=temp
function temp:inject(func,i)
if i then
table.insert(self.__Link,i,func)
else
table.insert(self.__Link,func)
end
end
function temp:consume(func)
for i=1,#self.__Link do
if self.__Link[i]==self.__Main then
self.__Link[i]=func
self.__self.__Main=func
return true
end
end
return false
end
setmetatable(temp,mt)
return temp
else
return "arg1 must be a table or a function"
end
end
function Library.convert(...)
local temp,rets={...},{}
for i=1,#temp do
if type(temp[i])=="function" then
table.insert(rets,Library.inject(temp[i]))
else
error("Takes only functions and returns in order from functions given. arg # "..i.." is not a function!!! It is a "..type(temp[i]))
end
end
return unpack(rets)
end
local link={MainLibrary=Library}
Library.inject(Library,"meta",{
__Link=link,
__call=function(self,func) func(link) end,
})
local multi, thread = require("multi").init()
os.sleep = lovr.timer.sleep
multi.drawF = {}
function multi:onDraw(func, i)
i = i or 1
table.insert(self.drawF, i, func)
end
multi.OnKeyPressed = multi:newConnection()
multi.OnKeyReleased = multi:newConnection()
multi.OnErrHand = multi:newConnection()
multi.OnFocus = multi:newConnection()
multi.OnLoad = multi:newConnection()
multi.OnLog = multi:newConnection()
multi.OnPermission = multi:newConnection()
multi.OnResize = multi:newConnection()
multi.OnRestart = multi:newConnection()
multi.OnThreadError = multi:newConnection()
multi.OnDraw = multi:newConnection()
multi.OnTextInput = multi:newConnection()
multi.OnUpdate = multi:newConnection()
multi.OnQuit = multi:newConnection()
multi.OnPreLoad(function()
local function Hook(func, conn)
if lovr[func] ~= nil then
lovr[func] = Library.convert(lovr[func])
lovr[func]:inject(function(...)
conn:Fire(...)
return {...}
end,1)
elseif lovr[func] == nil then
lovr[func] = function(...)
conn:Fire(...)
end
end
end
Hook("quit", multi.OnQuit)
Hook("keypressed", multi.OnKeyPressed)
Hook("keyreleased", multi.OnKeyReleased)
Hook("focus", multi.OnFocus)
Hook("log", multi.OnLog)
Hook("errhand", multi.OnErrHand)
Hook("load", multi.OnLoad)
Hook("draw", multi.OnDraw)
Hook("textinput", multi.OnTextInput)
Hook("update", multi.OnUpdate)
Hook("permission", multi.OnPermission)
Hook("resize", multi.OnResize)
Hook("restart", multi.OnRestart)
Hook("threaderror", multi.OnThreadError)
multi.OnDraw(function()
for i = 1, #multi.drawF do
lovr.graphics.setColor(255, 255, 255, 255)
multi.drawF[i]()
end
end)
end)
function multi:lovrloop(light)
local link
link = multi:newThread(function()
local mainloop = lovr.run()
while true do
thread.yield()
pcall(mainloop)
end
end).OnError(function(...)
print(...)
end)
if light==false then
multi:mainloop()
else
multi:lightloop()
end
end
multi.OnQuit(function()
multi.Stop()
lovr.event.quit()
end)
return multi
-2437
View File
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
package = "multi"
version = "15.2-0"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v15.2.0",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. Features non coroutine based multi-tasking, coroutine based multi-tasking, and system threading (Requires use of an integration).
Check github for documentation.
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
["multi"] = "multi/init.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager/init.lua",
["multi.integration.lanesManager.extensions"] = "multi/integration/lanesManager/extensions.lua",
["multi.integration.lanesManager.threads"] = "multi/integration/lanesManager/threads.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager/init.lua",
["multi.integration.loveManager.extensions"] = "multi/integration/loveManager/extensions.lua",
["multi.integration.loveManager.threads"] = "multi/integration/loveManager/threads.lua",
--["multi.integration.lovrManager"] = "multi/integration/lovrManager/init.lua",
--["multi.integration.lovrManager.extensions"] = "multi/integration/lovrManager/extensions.lua",
--["multi.integration.lovrManager.threads"] = "multi/integration/lovrManager/threads.lua",
["multi.integration.pesudoManager"] = "multi/integration/pesudoManager/init.lua",
["multi.integration.pesudoManager.extensions"] = "multi/integration/pesudoManager/extensions.lua",
["multi.integration.pesudoManager.threads"] = "multi/integration/pesudoManager/threads.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.threading"] = "multi/integration/threading.lua",
--["multi.integration.networkManager"] = "multi/integration/networkManager.lua",
}
}
+39
View File
@@ -0,0 +1,39 @@
package = "multi"
version = "15.2-1"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v15.2.1",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. Features non coroutine based multi-tasking, coroutine based multi-tasking, and system threading (Requires use of an integration).
Check github for documentation.
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
["multi"] = "multi/init.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager/init.lua",
["multi.integration.lanesManager.extensions"] = "multi/integration/lanesManager/extensions.lua",
["multi.integration.lanesManager.threads"] = "multi/integration/lanesManager/threads.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager/init.lua",
["multi.integration.loveManager.extensions"] = "multi/integration/loveManager/extensions.lua",
["multi.integration.loveManager.threads"] = "multi/integration/loveManager/threads.lua",
--["multi.integration.lovrManager"] = "multi/integration/lovrManager/init.lua",
--["multi.integration.lovrManager.extensions"] = "multi/integration/lovrManager/extensions.lua",
--["multi.integration.lovrManager.threads"] = "multi/integration/lovrManager/threads.lua",
["multi.integration.pesudoManager"] = "multi/integration/pesudoManager/init.lua",
["multi.integration.pesudoManager.extensions"] = "multi/integration/pesudoManager/extensions.lua",
["multi.integration.pesudoManager.threads"] = "multi/integration/pesudoManager/threads.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.threading"] = "multi/integration/threading.lua",
--["multi.integration.networkManager"] = "multi/integration/networkManager.lua",
}
}
+39
View File
@@ -0,0 +1,39 @@
package = "multi"
version = "15.3-0"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v15.3.0",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. Features non coroutine based multi-tasking, coroutine based multi-tasking, and system threading (Requires use of an integration).
Check github for documentation.
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
["multi"] = "init.lua",
["multi.integration.lanesManager"] = "integration/lanesManager/init.lua",
["multi.integration.lanesManager.extensions"] = "integration/lanesManager/extensions.lua",
["multi.integration.lanesManager.threads"] = "integration/lanesManager/threads.lua",
["multi.integration.loveManager"] = "integration/loveManager/init.lua",
["multi.integration.loveManager.extensions"] = "integration/loveManager/extensions.lua",
["multi.integration.loveManager.threads"] = "integration/loveManager/threads.lua",
--["multi.integration.lovrManager"] = "integration/lovrManager/init.lua",
--["multi.integration.lovrManager.extensions"] = "integration/lovrManager/extensions.lua",
--["multi.integration.lovrManager.threads"] = "integration/lovrManager/threads.lua",
["multi.integration.pesudoManager"] = "integration/pesudoManager/init.lua",
["multi.integration.pesudoManager.extensions"] = "integration/pesudoManager/extensions.lua",
["multi.integration.pesudoManager.threads"] = "integration/pesudoManager/threads.lua",
["multi.integration.luvitManager"] = "integration/luvitManager.lua",
["multi.integration.threading"] = "integration/threading.lua",
--["multi.integration.networkManager"] = "integration/networkManager.lua",
}
}
-113
View File
@@ -1,113 +0,0 @@
--package.path = "./?/init.lua;"..package.path
multi,thread = require("multi"):init()
func = thread:newFunction(function(count)
local a = 0
while true do
a = a + 1
thread.sleep(.5)
thread.pushStatus(a,count)
if a == count then break end
end
return "Done"
end)
multi:newThread("test",function()
local ret = func(10)
local ret2 = func(15)
local ret3 = func(20)
ret.OnStatus(function(part,whole)
print("Ret1: ",math.ceil((part/whole)*1000)/10 .."%")
end)
ret2.OnStatus(function(part,whole)
print("Ret2: ",math.ceil((part/whole)*1000)/10 .."%")
end)
ret3.OnStatus(function(part,whole)
print("Ret3: ",math.ceil((part/whole)*1000)/10 .."%")
end)
thread.hold(ret2.OnReturn + ret.OnReturn + ret3.OnReturn)
print("Function Done!")
os.exit()
end)
--GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your environment and uses what's available
func2 = thread:newFunction(function()
thread.sleep(3)
print("Hello World!")
return true
end,true) -- set holdme to true
func2:holdMe(false) -- reset holdme to false
print("Calling func...")
print(func2())
test = thread:newFunction(function(a,b)
thread.sleep(1)
return a,b
end)
print(test(1,2).connect(function(...)
print(...)
end))
test:Pause()
print(test(1,2).connect(function(...)
print(...)
end))
test:Resume()
print(test(1,2).connect(function(...)
print(...)
end))
test = thread:newFunction(function()
return 1,2,nil,3,4,5,6,7,8,9
end,true)
print(test())
multi:newThread("testing",function()
print("#Test = ",test())
print(thread.hold(function()
print("Hello!")
return false
end,{
interval = 2,
cycles = 3
})) -- End result, 3 attempts within 6 seconds. If still false then timeout
print("held")
end).OnError(function(...)
print(...)
end)
sandbox = multi:newProcessor("Test Processor")
sandbox:newTLoop(function()
print("testing...")
end,1)
test2 = multi:newTLoop(function()
print("testing2...")
end,1)
sandbox:newThread("Test Thread",function()
local a = 0
while true do
thread.sleep(1)
a = a + 1
print("Thread Test: ".. multi.getCurrentProcess().Name)
if a == 10 then
sandbox.Stop()
end
end
end).OnError(function(...)
print(...)
end)
multi:newThread("Test Thread",function()
while true do
thread.sleep(1)
print("Thread Test: ".. multi.getCurrentProcess().Name)
end
end).OnError(function(...)
print(...)
end)
sandbox.Start()
multi:mainloop()
-3
View File
@@ -1,3 +0,0 @@
return function objectTests(multi,thread)
print("Testing Alarms!")
end
+168 -4
View File
@@ -1,4 +1,9 @@
package.path="../?.lua;../?/init.lua;../?.lua;../?/?/init.lua;"..package.path if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
package.path="multi/?.lua;multi/?/init.lua;multi/?.lua;multi/?/?/init.lua;"..package.path
require("lldebugger").start()
else
package.path = "../?/init.lua;../?.lua;"..package.path
end
--[[ --[[
This file runs all tests. This file runs all tests.
Format: Format:
@@ -15,7 +20,166 @@ package.path="../?.lua;../?/init.lua;../?.lua;../?/?/init.lua;"..package.path
The expected and actual should "match" (Might be impossible when playing with threads) The expected and actual should "match" (Might be impossible when playing with threads)
This will be pushed directly to the master as tests start existing. This will be pushed directly to the master as tests start existing.
]] ]]
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init{print=true}--{priority=true}
function runTest(path) local good = false
local proc = multi:newProcessor("Test",true)
proc:newAlarm(3):OnRing(function()
good = true
end)
runTest = thread:newFunction(function()
local alarms,tsteps,steps,loops,tloops,updaters,events=false,0,0,0,0,0,false
print("Testing Basic Features. If this fails most other features will probably not work!")
proc:newAlarm(2):OnRing(function(a)
alarms = true
a:Destroy()
end)
proc:newTStep(1,10,1,.1):OnStep(function(t)
tsteps = tsteps + 1
end):OnEnd(function(step)
step:Destroy()
end)
proc:newStep(1,10):OnStep(function(s)
steps = steps + 1
end):OnEnd(function(step)
step:Destroy()
end)
local loop = proc:newLoop(function(l)
loops = loops + 1
end)
proc:newTLoop(function(t)
tloops = tloops + 1
end,.1)
local updater = proc:newUpdater(1):OnUpdate(function()
updaters = updaters + 1
end)
local event = proc:newEvent(function()
return alarms
end)
event.OnEvent(function(evnt)
evnt:Destroy()
events = true
print("Alarms: Ok")
print("Events: Ok")
if tsteps == 10 then print("TSteps: Ok") else print("TSteps: Bad!") end
if steps == 10 then print("Steps: Ok") else print("Steps: Bad!") end
if loops > 100 then print("Loops: Ok") else print("Loops: Bad!") end
if tloops > 10 then print("TLoops: Ok") else print("TLoops: Bad!") end
if updaters > 100 then print("Updaters: Ok") else print("Updaters: Bad!") end
end)
thread.hold(event.OnEvent)
print("Starting Connection and Thread tests!")
func = thread:newFunction(function(count)
print("Starting Status test: ",count)
local a = 0
while true do
a = a + 1
thread.sleep(.1)
thread.pushStatus(a,count)
if a == count then break end
end
return "Done", true, math.random(1,10000)
end)
local ret = func(10)
local ret2 = func(15)
local ret3 = func(20)
local s1,s2,s3 = 0,0,0
ret.OnError(function(...)
print("Func 1:",...)
end)
ret2.OnError(function(...)
print("Func 2:",...)
end)
ret3.OnError(function(...)
print("Func 3:",...)
end)
ret.OnStatus(function(part,whole)
s1 = math.ceil((part/whole)*1000)/10
end)
ret2.OnStatus(function(part,whole)
s2 = math.ceil((part/whole)*1000)/10
end)
ret3.OnStatus(function(part,whole)
s3 = math.ceil((part/whole)*1000)/10
end)
ret.OnReturn(function(...)
print("Done 1",...)
end)
ret2.OnReturn(function(...)
print("Done 2",...)
end)
ret3.OnReturn(function(...)
print("Done 3",...)
end)
local err, timeout = thread.hold(ret.OnReturn * ret2.OnReturn * ret3.OnReturn)
if s1 == 100 and s2 == 100 and s3 == 100 then
print("Threads: All tests Ok")
else
if s1>0 and s2>0 and s3 > 0 then
print("Thread OnStatus: Ok")
else
print("Threads OnStatus or thread.hold(conn) Error!")
end
if timeout then
print("Connection Error!")
else
print("Connection Test 1: Ok")
end
print("Connection holding Error!")
end
conn1 = proc:newConnection()
conn2 = proc:newConnection()
conn3 = proc:newConnection()
local c1,c2,c3,c4 = false,false,false,false
local a = conn1(function()
c1 = true
end)
local b = conn2(function()
c2 = true
end)
local c = conn3(function()
c3 = true
end)
local d = conn3(function()
c4 = true
end)
conn1:Fire()
conn2:Fire()
conn3:Fire()
if c1 and c2 and c3 and c4 then
print("Connection Test 2: Ok")
else
print("Connection Test 2: Error")
end
c3 = false
c4 = false
d:Destroy()
conn3:Fire()
if c3 and not(c4) then
print("Connection Test 3: Ok")
else
print("Connection Test 3: Error removing connection")
end
os.exit() -- End of tests
end)
print(runTest().OnError(function(...)
print("Error: Something went wrong with the test!")
print(...)
os.exit(1)
end))
print("Pumping proc")
while true do
proc.run()
end end
+133
View File
@@ -0,0 +1,133 @@
package.path = "../?/init.lua;../?.lua;"..package.path
multi, thread = require("multi"):init{print=true,findopt=true}
GLOBAL, THREAD = require("multi.integration.lanesManager"):init()
multi:getOptimizationConnection()(function(msg)
print(msg)
end)
local conn1, conn2, conn3 = multi:newConnection(), multi:newConnection():fastMode(), multi:newConnection()
local link = conn1(function()
print("Conn1, first")
end)
local link2 = conn1(function()
print("Conn1, second")
end)
local link3 = conn1(function()
print("Conn1, third")
end)
local link4 = conn2(function()
print("Conn2, first")
end)
local link5 = conn2(function()
print("Conn2, second")
end)
local link6 = conn2(function()
print("Conn2, third")
end)
print("All conns\n-------------")
conn1:Fire()
conn2:Fire()
conn1:Unconnect(link3)
conn2:Unconnect(link6)
print("All conns Edit\n---------------------")
conn1:Fire()
conn2:Fire()
-- thread:newThread(function()
-- print("Awaiting status")
-- thread.hold(conn1 + (conn2 * conn3))
-- print("Conn or Conn2 and Conn3")
-- end)
-- multi:newAlarm(1):OnRing(function()
-- print("Conn")
-- conn1:Fire()
-- end)
-- multi:newAlarm(2):OnRing(function()
-- print("Conn2")
-- conn2:Fire()
-- end)
-- multi:newAlarm(3):OnRing(function()
-- print("Conn3")
-- conn3:Fire()
-- end)
-- local conn = multi:newSystemThreadedConnection("conn"):init()
-- multi:newSystemThread("Thread_Test_1", function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:mainloop()
-- end)
-- multi:newSystemThread("Thread_Test_2", function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:newAlarm(2):OnRing(function()
-- console.print("Fire 2!!!")
-- conn:Fire(4,5,6)
-- THREAD.kill()
-- end)
-- multi:mainloop()
-- end)
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print("Mainloop conn got triggered!",a,b,c)
-- end)
-- alarm = multi:newAlarm(1)
-- alarm:OnRing(function()
-- console.print("Fire 1!!!")
-- conn:Fire(1,2,3)
-- end)
-- alarm = multi:newAlarm(3):OnRing(function()
-- multi:newSystemThread("Thread_Test_3",function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:newAlarm(4):OnRing(function()
-- console.print("Fire 3!!!")
-- conn:Fire(7,8,9)
-- end)
-- multi:mainloop()
-- end)
-- end)
-- multi:newSystemThread("Thread_Test_4",function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local conn2 = multi:newConnection()
-- local console = THREAD.getConsole()
-- multi:newAlarm(2):OnRing(function()
-- conn2:Fire()
-- end)
-- multi:newThread(function()
-- console.print("Conn Test!")
-- thread.hold(conn + conn2)
-- console.print("It held!")
-- end)
-- multi:mainloop()
-- end)
-- multi:mainloop()