The resource loading... loading...

Threads

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.

threading

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.

Thread

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}

getThread

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}

mainThread

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}

currentThread

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}

Lock

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}

Condition

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}

Event

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}

Dict

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}

pending

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

Thread objects can be created or returned by threading.Thread(), threading.getThread(), threading.mainThread(), and threading.currentThread().

peekMessage

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}

postMessage

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}

join

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:

  • id: Thread Id.
  • terminated: Whether the thread is forced to end.
  • elapsed: The running time of the thread in nanoseconds.
  • ret: The return value of the thread function.

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}

terminate

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}

getData

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}

setData

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}

id

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}

name

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}

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}

ThreadLock

Thread lock object, used for multi-thread synchronization processing.

acquire

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}

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}

ThreadEvent

Event object, used for multi-threaded event notification and signal.

set

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}

clear

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}

wait

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}

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}

ThreadCondition

Condition object, used for multi-thread synchronization.

notify

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}

notifyAll

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}

wait

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}

acquire

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}

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}

ThreadDict

Dictionary object, used for data sharing.

get

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}

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