The FMZ Quant Trading Platform truly supports the multi-threaded function of the JavaScript
language strategy from the bottom of the system, and implements the following objects:
Objects | Directions | Remarks |
---|---|---|
threading | Multithreaded global object | Member functions: Thread , getThread , mainThread , etc. |
Thread | Thread object | Member functions: peekMessage , postMessage , join , etc. |
ThreadLock | Thread lock object | Member functions: acquire , release . They can be passed into the thread environment as parameters of the thread execution function. |
ThreadEvent | Event object | Member functions: set , clear , wait , isSet . They can be passed into the thread environment as a parameter of the thread execution function. |
ThreadCondition | Condition object | Member functions: notify , notifyAll , wait , acquire , release . They can be passed into the thread environment as a parameter of the thread execution function. |
ThreadDict | Dictionary object | Member functions: get , set . They can be passed into the thread environment as parameters of the thread execution function. |
The threading
object is a global multithreading management tool that provides functions such as creating concurrent threads, thread locks, and condition objects. This section introduces the member functions of the threading
object. This object is only supported by the JavaScript
language strategy.
The Thread()
function is used to create concurrent threads.
The Thread()
function returns a Thread
object, which is used to manage created concurrent threads, thread communication, etc.
Thread
object
Thread(func, …args) Thread(…items)
The parameter func
is a function for concurrent execution (passed by reference), and supports passing in anonymous functions. func
can accept multiple parameters, which will be passed in through ...args
during concurrent execution. Therefore, the parameter list of func
needs to be consistent with ...args
.
func
true
function
The parameter arg
is the actual parameter passed to func
(i.e. the concurrent thread execution function) when the callback is executed; there may be multiple parameters arg
, and the parameter list of func
needs to be consistent with ...args
.
arg
false
string, number, bool, object, array, function, null value and other types supported by the system
The parameter item
is an array containing the function references and their parameters to be executed concurrently. Multiple groups of item
parameters can be passed in when calling the Thread
function.
item true array
function test1(a, b, c) {
Log("test1:", a, b, c)
}
function main() {
var t1 = threading.Thread(test1, 1, 2, 3)
var t2 = threading.Thread(function (msg) {
Log("msg:", msg)
}, "Hello thread2")
t1.join()
t2.join()
}
Create concurrent threads for both a custom function and an anonymous function.
function test1(msg) {
Log("msg:", msg)
test2("Hello test2")
}
function main() {
var t1 = threading.Thread(
[function(a, b, c) {Log(a, b, c)}, 1, 2, 3],
[test1, "Hello test1"],
[`function test2(msg) {Log("msg:", msg)}`])
t1.join()
}
Use the Thread(...items)
form to create concurrent threads and execute multiple functions sequentially.
function ml(input) {
const net = new brain.NeuralNetwork()
net.train([
{ input: [0, 0], output: [0] },
{ input: [0, 1], output: [1] },
{ input: [1, 0], output: [1] },
{ input: [1, 1], output: [0] },
])
return net.run(input)
}
function main() {
var ret = threading.Thread([ml, [1, 0]], [HttpQuery("https://unpkg.com/brain.js")]).join()
// ret: {"id":1,"terminated":false,"elapsed":337636000,"ret":{"0":0.9339330196380615}}
Log(ret)
}
It supports passing in function strings and can import external libraries dynamically for concurrent computing.
The thread function func
passed into the Thread()
function for concurrent execution runs in an isolated environment, so variables outside the thread cannot be directly referenced, and compilation will fail when referenced. At the same time, references to other closure functions are not supported within the thread. All APIs provided by the platform can be called within the thread, but other user-defined functions cannot be called.
It supports backtesting system and live trading environment. All concurrent thread-related functions are only supported as code compatibility in the backtesting system and will not be actually executed by concurrent threads, so they will not be repeated in this chapter.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The getThread()
function is used to get the thread object based on the specified thread Id.
The getThread()
function returns the Thread
object with the threadId specified by the parameter
Thread
object
getThread(threadId)
The parameter threadId
is the thread object ID. Get the corresponding thread object by specifying the parameter.
threadId true number
function main() {
var t1 = threading.Thread(function () {
Log("Hello thread1")
})
// The Thread object has a method: id(), which is used to get the thread ID. You can view the section of the document corresponding to the Thread object.
var threadId = t1.id()
var threadName = t1.name()
Log("threadId:", threadId, ", threadName:", threadName)
var t2 = threading.getThread(threadId)
Log(`threadId == t2.id():`, threadId == t2.id(), `, threadName == t2.name():`, threadName == t2.name())
}
Get the specified thread object through threadId
.
It supports backtesting system and live trading environment.
If the thread you want to obtain has been executed and released, you cannot use threading.getThread(threadId)
to obtain the thread object of the thread.
{@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The mainThread()
function is used to obtain the thread object of the main thread, that is, the thread where the main()
function in the strategy is located.
The mainThread()
function returns the thread object of the main thread.
Thread
object
mainThread()
function main() {
Log("The threadId of the main thread:", threading.mainThread().id())
}
Get the Thread
object of the main thread and output the threadId
of the main thread.
function test() {
Log("Output the main thread ID in the test function:", threading.mainThread().id())
}
function main() {
var t1 = threading.Thread(test)
t1.join()
}
The thread object of the main thread can also be obtained in concurrent threads.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The currentThread()
function is used to get the thread object of the current thread.
The currentThread()
function returns the thread object of the current thread.
Thread
object
currentThread()
function test() {
Log("Id of the current thread:", threading.currentThread().id())
}
function main() {
var t1 = threading.Thread(test)
t1.join()
}
Get the Thread
object of the current thread and output the threadId
of the current thread.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The Lock()
function is used to create a thread lock object.
The Lock()
function returns a thread lock object.
ThreadLock
object
Lock()
function consumer(productionQuantity, dict, lock) {
for (var i = 0; i < productionQuantity; i++) {
lock.acquire()
var count = dict.get("count")
Log("consumer:", count)
Sleep(1000)
lock.release()
}
}
function producer(productionQuantity, dict, lock) {
for (var i = 0; i < productionQuantity; i++) {
lock.acquire()
dict.set("count", i)
Log("producer:", i)
Sleep(1000)
lock.release()
}
}
function main() {
var dict = threading.Dict()
dict.set("count", -1)
var lock = threading.Lock()
var productionQuantity = 10
var producerThread = threading.Thread(producer, productionQuantity, dict, lock)
var consumerThread = threading.Thread(consumer, productionQuantity, dict, lock)
consumerThread.join()
producerThread.join()
}
Two concurrent threads access a common resource.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The Condition()
function is used to create a condition variable object, which is used to achieve synchronization and communication between threads in a multi-threaded concurrent environment. Through Condition()
, a thread can wait when certain conditions are not met until another thread notifies it that the condition has been met.
The Condition()
function returns a ThreadCondition
object.
ThreadCondition
object
Condition()
function consumer(productionQuantity, dict, condition) {
for (var i = 0; i < productionQuantity; i++) {
condition.acquire()
while (dict.get("array").length == 0) {
condition.wait()
}
var arr = dict.get("array")
var count = arr.shift()
dict.set("array", arr)
Log("consumer:", count, ", array:", arr)
condition.release()
Sleep(1000)
}
}
function producer(productionQuantity, dict, condition) {
for (var i = 0; i < productionQuantity; i++) {
condition.acquire()
var arr = dict.get("array")
arr.push(i)
dict.set("array", arr)
Log("producer:", i, ", array:", arr)
condition.notify()
condition.release()
Sleep(1000)
}
}
function main() {
var dict = threading.Dict()
dict.set("array", [])
var condition = threading.Condition()
var productionQuantity = 10
var producerThread = threading.Thread(producer, productionQuantity, dict, condition)
var consumerThread = threading.Thread(consumer, productionQuantity, dict, condition)
consumerThread.join()
producerThread.join()
}
Two concurrent threads access a common resource.
The backtesting system does not implement this functionality, it only defines it.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The Event()
function is used to create a thread event object, which is used for synchronization between threads, allowing one thread to wait for notification or signal from another thread.
The Event()
function returns a ThreadEvent
object.
ThreadEvent
object
Event()
function consumer(productionQuantity, dict, pEvent, cEvent) {
for (var i = 0; i < productionQuantity; i++) {
while (dict.get("array").length == 0) {
pEvent.wait()
}
if (pEvent.isSet()) {
pEvent.clear()
}
var arr = dict.get("array")
var count = arr.shift()
dict.set("array", arr)
Log("consumer:", count, ", array:", arr)
cEvent.set()
Sleep(1000)
}
}
function producer(productionQuantity, dict, pEvent, cEvent) {
for (var i = 0; i < productionQuantity; i++) {
while (dict.get("array").length != 0) {
cEvent.wait()
}
if (cEvent.isSet()) {
cEvent.clear()
}
var arr = dict.get("array")
arr.push(i)
dict.set("array", arr)
Log("producer:", i, ", array:", arr)
pEvent.set()
Sleep(1000)
}
}
function main() {
var dict = threading.Dict()
dict.set("array", [])
var pEvent = threading.Event()
var cEvent = threading.Event()
var productionQuantity = 10
var producerThread = threading.Thread(producer, productionQuantity, dict, pEvent, cEvent)
var consumerThread = threading.Thread(consumer, productionQuantity, dict, pEvent, cEvent)
consumerThread.join()
producerThread.join()
}
Two concurrent threads access a common resource.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The Dict()
function is used to create a dictionary object for passing to concurrent threads.
The Dict()
function returns a ThreadDict
object.
ThreadDict
object
Dict()
function threadFun1(obj) {
obj["age"] = 100
while (true) {
Log("threadFun1 obj:", obj)
Sleep(5000)
}
}
function threadFun2(obj) {
while (true) {
Log("threadFun2 obj:", obj)
Sleep(5000)
}
}
function main() {
var obj = {"age": 10}
var t1 = threading.Thread(threadFun1, obj)
var t2 = threading.Thread(threadFun2, obj)
t1.join()
t2.join()
}
Pass a normal object to the concurrent thread execution function to test whether modifying the key value of the object will cause changes in the key value of the object in other threads.
function threadFun1(threadDict) {
threadDict.set("age", 100)
while (true) {
Log(`threadFun1 threadDict.get("age"):`, threadDict.get("age"))
Sleep(5000)
}
}
function threadFun2(threadDict) {
while (true) {
Log(`threadFun2 threadDict.get("age"):`, threadDict.get("age"))
Sleep(5000)
}
}
function main() {
var threadDict = threading.Dict()
threadDict.set("age", 10)
var t1 = threading.Thread(threadFun1, threadDict)
var t2 = threading.Thread(threadFun2, threadDict)
t1.join()
t2.join()
}
Pass the ThreadDict
object created by the Dict()
function to the concurrent thread execution function, and test whether modifying the key value of the object will cause the key value of the object in other threads to change.
When a common object is passed to a concurrent thread function, it is passed as a deep copy. Modifying the key value in a concurrent thread will not affect the dictionary in other threads.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}
The pending
function is used to obtain the number of concurrent threads running in the current strategy program.
The pending()
function returns the number of concurrent threads that the current strategy program is running.
number
pending()
function threadFun1() {
Log("threadFun1")
Sleep(3000)
}
function threadFun2() {
for (var i = 0; i < 3; i++) {
LogStatus(_D(), "print from threadFun2")
Sleep(3000)
}
}
function main() {
Log(`begin -- threading.pending():`, threading.pending())
var t1 = threading.Thread(threadFun1)
var t2 = threading.Thread(threadFun2)
Log(`after threading.Thread -- threading.pending():`, threading.pending())
t1.join()
t2.join()
Log(`after thread.join -- threading.pending():`, threading.pending())
}
Create two concurrently running threads and call the pending()
function at different time nodes.
When the strategy main()
function starts running, calling the function pending()
directly will return 1, because the main thread where the strategy main()
function is located is also a pending thread.
It supports backtesting system and live trading environment.
{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/eventLoop eventLoop}
Thread
objects can be created or returned by threading.Thread()
, threading.getThread()
, threading.mainThread()
, and threading.currentThread()
.
The peekMessage()
function is used to get a message from a thread.
The peekMessage()
function returns the message received by the thread associated with the current thread object.
string, number, bool, object, array, null value and other types supported by the system
peekMessage() peekMessage(timeout)
The parameter timeout
is the timeout setting. It will block and wait for the number of milliseconds set by the parameter and return data. If there is no data and the timeout exceeds the limit, a null value will be returned. If timeout
is set to 0 or the timeout
parameter is not passed, it means that the process will block and wait until data is received from the channel. If timeout
is set to -1, it means that the process will not block and return data immediately. If there is no data, a null value will be returned.
timeout false number
function main() {
var t1 = threading.Thread(function() {
for (var i = 0; i < 10; i++) {
Log("thread1 postMessage():", i)
threading.mainThread().postMessage(i)
Sleep(500)
}
})
while (true) {
var msg = threading.currentThread().peekMessage()
Log("main peekMessage():", msg)
if (msg == 9) {
break
}
Sleep(1000)
}
t1.join()
}
Send messages to the main thread from a concurrent thread.
When writing programs, we need to pay attention to thread deadlock problems.
{@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The postMessage()
function is used to send a message to a thread.
postMessage(msg)
The parameter msg
is the message to be sent.
msg true Any type supported by the system, such as string, number, bool, object, array, null value, etc.
function main() {
var t1 = threading.Thread(function() {
for (var i = 0; i < 10; i++) {
Log("thread1 postMessage():", i)
threading.mainThread().postMessage(i)
Sleep(500)
}
})
for (var i = 0; i < 10; i++) {
var event = threading.mainThread().eventLoop()
Log("main event:", event)
Sleep(500)
}
t1.join()
}
Send messages in concurrent threads and use eventLoop()
to receive message notifications.
When a thread’s execution function calls the postMessage()
function to send a signal or data, a message event is also generated. We can use the eventLoop()
function to receive message notifications.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The join()
function is used to wait for the thread to exit and reclaim system resources.
The ThreadRet
object contains data about the execution result. The properties include the following:
ThreadRet
object
join() join(timeout)
The timeout
parameter is used to set the timeout in milliseconds for waiting for the thread to finish. When the timeout
parameter is set to 0 or the timeout
parameter is not set, the join()
function will block and wait until the thread finishes executing. When the timeout
parameter is set to -1, the join()
function will return immediately.
timeout false number
function main() {
var t1 = threading.Thread(function() {
Log("Hello thread1")
Sleep(5000)
})
var ret = t1.join(1000)
Log("ret:", ret) // ret: undefined
ret = t1.join()
Log("ret:", ret) // ret: {"id":1,"terminated":false,"elapsed":5003252000}
}
Test the join()
function for timeout and output the return value.
The join()
function times out and returns undefined
.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The terminate()
function is used to forcibly terminate a thread and release the hardware resources used by the created thread.
terminate()
function main() {
var t1 = threading.Thread(function() {
for (var i = 0; i < 10; i++) {
Log("thread1 i:", i)
Sleep(1000)
}
})
Sleep(3000)
t1.terminate()
Log("after t1.terminate()")
while (true) {
LogStatus(_D())
Sleep(1000)
}
}
Terminate the execution of a thread forcefully. After forcibly terminating a thread, there will be no output from this thread in the log.
For threads that are forcibly terminated by the terminate()
function, we can no longer use the join()
function to wait for them to terminate.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The getData()
function is used to access variables recorded in the thread environment. The data is valid when the thread has not executed the join()
function (waiting for exit success) and has not executed the terminate()
function (terminating the thread forcibly).
The getData()
function returns the key value corresponding to the key
parameter in the key-value pair stored in the current thread context.
string, number, bool, object, array, null value and other types supported by the system
getData() getData(key)
The key
parameter is the key name of the stored key-value pair.
key true string
function main() {
var t1 = threading.Thread(function() {
for (var i = 0; i < 5; i++) {
threading.currentThread().setData("count", i)
Log(`setData("count"):`, i)
Sleep(1000)
}
})
for (var i = 0; i < 5; i++) {
var count = threading.getThread(t1.id()).getData("count")
Log(`getData("count"):`, count)
Sleep(1000)
}
t1.join()
}
Record the value of the key count
in the concurrent thread environment, and then read the key value of count
in the main thread.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The setData()
function is used to store variables in the thread context.
setData(key, value)
The key
parameter is used to specify the key name of the stored key-value pair.
key
true
string
The value
parameter is used to specify the key value of the stored key-value pair.
value true Any type supported by the system, such as string, number, bool, object, array, null value, etc.
function main() {
var t1 = threading.Thread(function() {
threading.currentThread().setData("data", 100)
})
Sleep(1000)
Log(`t1.getData("data"):`, t1.getData("data"))
t1.join()
}
Set the key-value pair in the concurrent thread and read the key-value pair in the main thread.
The data is valid when the thread has not executed the join()
function (waiting for exit success) and has not executed the terminate()
function (terminating the thread forcibly). The value of the parameter value
must be a serializable variable.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The id()
function is used to return the threadId
of the current multithreaded object instance.
The return value of the id()
function is threadId
.
number
id()
function main() {
var t1 = threading.Thread(function() {
threading.currentThread().setData("data", 100)
})
Log(`t1.id():`, t1.id())
t1.join()
}
Create a concurrently running thread and output the threadId
of this concurrent thread in the main thread.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}
The name()
function is used to return the name of the current multithreaded object instance.
The name()
function returns the concurrent thread name.
string
name()
function main() {
var t1 = threading.Thread(function() {
threading.currentThread().setData("data", 100)
})
Log(`t1.name():`, t1.name()) // t1.name(): Thread-1
t1.join()
}
Create a concurrent thread and output the name of the concurrent thread in the main thread.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/eventLoop eventLoop}
The eventLoop()
function is used to listen for events received by the thread.
The eventLoop()
function returns the event information received by the current thread. See Event Information Structure.
object, null value
eventLoop() eventLoop(timeout)
The parameter timeout
is the timeout setting in milliseconds. If the parameter timeout
is set to 0, it will wait for an event to occur before returning. If it is greater than 0, it will set the event waiting timeout. If it is less than 0, it will return the latest event immediately.
timeout false number
function main() {
var t1 = threading.Thread(function() {
while (true) {
var eventMsg = threading.currentThread().eventLoop() // Blocking wait
// 2024-11-14 10:14:18 thread1 eventMsg: {"Seq":1,"Event":"thread","ThreadId":0,"Index":1,"Queue":0,"Nano":1731550458699947000}
Log(_D(), "thread1 eventMsg:", eventMsg)
}
})
var t2 = threading.Thread(function() {
while (true) {
var eventMsg = threading.currentThread().eventLoop(-1) // Return immediately
Log(_D(), "thread2 eventMsg:", eventMsg)
Sleep(5000)
}
})
var t3 = threading.Thread(function() {
while (true) {
var eventMsg = threading.currentThread().eventLoop(3000) // Set a 3 second timeout
Log(_D(), "thread3 eventMsg:", eventMsg)
}
})
t1.postMessage("Hello ", t1.name())
t2.postMessage("Hello ", t2.name())
t3.postMessage("Hello ", t3.name())
t1.join()
t2.join()
t3.join()
}
Execute three threads concurrently and output the received event information. If the timeout occurs or the function returns immediately, the output value is null.
The processing mechanism of the eventLoop()
function is the same as the global function EventLoop()
.
{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}
Thread lock object, used for multi-thread synchronization processing.
The acquire()
function is used to request a thread lock (lock).
acquire()
Please refer to the threading.Lock()
section for examples.
The acquire()
function is used to request a thread lock. When a thread calls the acquire()
function of a thread lock object, it attempts to acquire the lock. If the lock is not currently held by another thread, the calling thread successfully acquires the lock and continues execution. If the lock is already held by another thread, the thread calling acquire()
will be blocked until the lock is released.
{@fun/Threads/threading/Lock Lock}, {@fun/Threads/ThreadLock/release release}
The release()
function is used to release a thread lock (unlock).
release()
function consumer(productionQuantity, dict, pLock, cLock) {
for (var i = 0; i < productionQuantity; i++) {
pLock.acquire()
cLock.acquire()
var arr = dict.get("array")
var count = arr.shift()
dict.set("array", arr)
Log("consumer:", count, ", array:", arr)
cLock.release()
Sleep(1000)
pLock.release()
}
}
function producer(productionQuantity, dict, pLock, cLock) {
for (var i = 0; i < productionQuantity; i++) {
cLock.acquire() // cLock.acquire() placed after pLock.acquire() will not cause deadlock
pLock.acquire()
var arr = dict.get("array")
arr.push(i)
dict.set("array", arr)
Log("producer:", i, ", array:", arr)
pLock.release()
Sleep(1000)
cLock.release()
}
}
function main() {
var dict = threading.Dict()
dict.set("array", [])
var pLock = threading.Lock()
var cLock = threading.Lock()
var productionQuantity = 10
var producerThread = threading.Thread(producer, productionQuantity, dict, pLock, cLock)
var consumerThread = threading.Thread(consumer, productionQuantity, dict, pLock, cLock)
consumerThread.join()
producerThread.join()
}
Testing deadlock scenarios
It should be noted that improper use of thread locks may lead to deadlock.
{@fun/Threads/threading/Lock Lock}, {@fun/Threads/ThreadLock/acquire acquire}
Event object, used for multi-threaded event notification and signal.
The set()
function is used to notify events (set signals).
set()
Please refer to the threading.Event()
section for examples.
If the signal has been set using set()
, it cannot be set again. We need to clear the signal and set it again.
{@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/wait wait}, {@fun/Threads/ThreadEvent/isSet isSet}
The clear()
function is used to clear the signal.
clear()
Please refer to the threading.Event()
section for examples.
{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/wait wait}, {@fun/Threads/ThreadEvent/isSet isSet}
The wait()
function is used to set an event (signal) wait, and will block before the event (signal) is set; it supports setting a timeout parameter.
The wait()
function returns whether the timeout has occurred. If so, it returns a true value.
bool
wait() wait(timeout)
The timeout
parameter is used to set the waiting timeout in milliseconds.
timeout false number
function main() {
var event = threading.Event()
var t1 = threading.Thread(function(event) {
var ret = event.wait(100)
Log(`event.wait(100):`, ret)
ret = event.wait()
Log(`event.wait():`, ret)
}, event)
Sleep(1000)
event.set()
t1.join()
}
Test the return value of the wait()
function.
{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/isSet isSet}
The isSet()
function is used to determine whether an event (signal) has been set.
The isSet()
function returns whether the event (signal) has been set; if the event (signal) has been set, it returns a true value.
bool
isSet()
Please refer to the threading.Event()
section for examples.
{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/wait wait}
Condition object, used for multi-thread synchronization.
The notify()
function is used to wake up a waiting thread (if any). Only threads that have called the wait()
method will be woken up.
notify()
function consumer(dict, condition) {
while (true) {
condition.acquire()
while (dict.get("array").length == 0) {
Log(threading.currentThread().name(), "wait()...", ", array:", dict.get("array"))
condition.wait()
}
var arr = dict.get("array")
var num = arr.shift()
Log(threading.currentThread().name(), ", num:", num, ", array:", arr, "#FF0000")
dict.set("array", arr)
Sleep(1000)
condition.release()
}
}
function main() {
var condition = threading.Condition()
var dict = threading.Dict()
dict.set("array", [])
var t1 = threading.Thread(consumer, dict, condition)
var t2 = threading.Thread(consumer, dict, condition)
var t3 = threading.Thread(consumer, dict, condition)
Sleep(1000)
var i = 0
while (true) {
condition.acquire()
var msg = ""
var arr = dict.get("array")
var randomNum = Math.floor(Math.random() * 5) + 1
if (arr.length >= 3) {
condition.notifyAll()
msg = "notifyAll"
} else {
arr.push(i)
dict.set("array", arr)
if (randomNum > 3 && arr.length > 0) {
condition.notify()
msg = "notify"
} else {
msg = "pass"
}
i++
}
Log(_D(), "randomNum:", randomNum, ", array:", arr, ", msg:", msg)
condition.release()
Sleep(1000)
}
}
Use the notify()
function to wake up the waiting thread.
The notify()
function wakes up a thread in the waiting queue.
When the notify()
function wakes up a thread, the thread will reacquire the thread lock.
{@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait}, {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}
The notifyAll()
function wakes up all waiting threads.
notifyAll()
Please refer to the ThreadCondition.notify()
section for examples.
The notifyAll()
function wakes up all waiting threads one by one, and the awakened threads reacquire the thread lock.
{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/wait wait}, {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}
The wait()
function is used to make a thread wait under certain designed conditions.
wait()
Please refer to the ThreadCondition.notify()
section for examples.
The wait()
function releases the thread lock and reacquires the thread lock when woken up.
{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}
The acquire()
function is used to request a thread lock (lock).
acquire()
Please refer to the ThreadCondition.notify()
section for examples.
Before using wait()
, you need to request the thread lock (lock) of the current condition object.
{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait}, {@fun/Threads/ThreadCondition/release release}
The release()
function is used to release a thread lock (unlock).
release()
Please refer to the ThreadCondition.notify()
section for examples.
After using wait()
, we need to release the thread lock (unlock) of the current condition object.
{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait}, {@fun/Threads/ThreadCondition/acquire acquire}
Dictionary object, used for data sharing.
The get()
function is used to get the key value recorded in the dictionary object.
The get()
function returns the value of the key specified by the key
parameter.
string, number, bool, object, array, null value and other types supported by the system
get(key)
The key
parameter is used to specify the key name corresponding to the key to be obtained.
key true string
function main() {
var event = threading.Event()
var dict = threading.Dict()
dict.set("data", 100)
var t1 = threading.Thread(function(dict, event) {
Log(`thread1, dict.get("data"):`, dict.get("data"))
event.set()
event.clear()
event.wait()
Log(`after main change data, thread1 dict.get("data"):`, dict.get("data"))
dict.set("data", 0)
}, dict, event)
event.wait()
dict.set("data", 99)
event.set()
event.clear()
t1.join()
Log(`main thread, dict.get("data"):`, dict.get("data"))
}
Use event objects to notify threads to read and modify data.
{@fun/Threads/ThreadDict/set set}
The set()
function is used to set a key-value pair.
set(key, value)
The parameter key
is used to set the key name to be modified.
key
true
string
The parameter value
is used to set the key value to be modified.
value true string, number, bool, object, array, null value and other types supported by the system
Please refer to the ThreadDict.get()
section for examples.
{@fun/Threads/ThreadDict/get get}
NetSettings Web3