Thread
Функции управления потоками
thread.list([table, monitor, all])
Вывести список всех потоков.
Аргументы:
-
table (необязательно): если true, список потоков возвращается в виде таблицы Lua, если false — список потоков выводится в консоль.
-
monitor (необязательно): если true, список потоков обновляется каждые 0,5 секунды. Разрешено только если table = false.
-
all (необязательно): если true, показывать все потоки. Если false (по умолчанию), показываются только lua потоки. Существуют 3 типа потоков:
- task: это задача FreeRTOS, управляемая непосредственно FreeRTOS. Эти типы задач соответствуют системным задачам.
- thread: это задача FreeRTOS, управляемая API pthread.
- lua: это задача FreeRTOS, управляемая модулем потоков Lua.
Возвращает:
-
если table равно false: ничего или исключение.
-
если table равно true: таблицу Lua с результатом списка потоков или исключение. Эта таблица представляет собой массив таблиц. Каждая запись соответствует потоку. Каждый поток содержит следующие поля:
- thid: идентификатор потока.
- type: тип потока, может быть task, thread или lua.
- name: имя потока.
- status: для lua потоков может быть либо run (запущен) или susp (приостановлен), а для других типов потоков пусто.
- core: ЦПУ, на котором закреплен поток.
- stack_size: назначенный размер стека (в байтах) для потока.
- free_stack: количество свободных байтов в стеке.
- used_stack: количество использованных байтов в стеке.
/ > thread.list()
-----------------------------------------------------------------------------------------
| | | | | | STACK
THID | TYPE | NAME | STATUS | CORE | PRIO | SIZE FREE USED
-----------------------------------------------------------------------------------------
1 lua lua run 0 20 10240 7632 2608 ( 25%)
0 task IDLE 1 0 1024 600 424 ( 41%)
0 task IDLE 0 0 1024 596 428 ( 41%)
0 task Tmr Svc 0 1 2048 1648 400 ( 19%)
0 task ipc0 0 24 1024 576 448 ( 43%)
0 task esp_timer 0 22 4096 3652 444 ( 10%)
0 task signal 0 21 768 312 456 ( 59%)
0 task ipc1 1 24 1024 500 524 ( 51%)
thread.start(function, [stack, priority, cpu, name])
Запустить новый поток.
Аргументы:
- function: функция, которую нужно выполнить в потоке.
- stack (необязательно): количество байтов, выделяемых для использования в качестве стека потока. Должно быть >= 2048.
- priority (необязательно): приоритет, с которым будет выполняться поток. Должен быть >= 3 и <= 25, где 3 — минимальный приоритет.
- cpu (необязательно): ЦПУ, на котором будет выполняться поток.
- name (необязательно): имя, присвоенное потоку, для целей отладки.
Возвращает: идентификатор потока или исключение. Этот идентификатор необходимо сохранить в переменной для дальнейших операций с ним.
-- Function to execute
f1 = function()
local led_pin = pio.GPIO4
pio.pin.setdir(pio.OUTPUT, led_pin)
while true do
pio.pin.sethigh(led_pin)
tmr.delayms(250)
pio.pin.setlow(led_pin)
tmr.delayms(250)
end
end
-- Start thread
th1 = thread.start(f1)
thread.self()
Получить идентификатор потока вызывающего потока.
Аргументы: нет.
Возвращает: идентификатор потока.
thread.start(function()
print("I'm: "..thread.self())
end)
thread.suspend([thread id])
Приостановить все потоки или конкретный поток. Эта функция приостанавливает выполнение базового потока операционной системы, оставаясь в памяти, пока он не будет возобновлен или остановлен.
Аргументы:
- thread id (идентификатор потока): этот аргумент необязателен. Если он не указан, функция приостанавливает все потоки, а если указан, приостанавливает указанный поток.
Возвращает: ничего.
-- Function to execute
f1 = function()
local led_pin = pio.GPIO4
pio.pin.setdir(pio.OUTPUT, led_pin)
while true do
pio.pin.sethigh(led_pin)
tmr.delayms(250)
pio.pin.setlow(led_pin)
tmr.delayms(250)
end
end
-- Start thread
th1 = thread.start(f1)
....
-- Suspend thread
thread.suspend(th1)
thread.resume([thread id])
Возобновить работу всех потоков или конкретного потока. Эта функция возобновляет выполнение базового потока операционной системы.
Аргументы:
- thread id (идентификатор потока): этот аргумент необязателен. Если он не указан, функция возобновляет работу всех потоков, а если указан, возобновляет работу указанного потока.
Возвращает: ничего.
-- Function to execute
f1 = function()
local led_pin = pio.GPIO4
pio.pin.setdir(pio.OUTPUT, led_pin)
while true do
pio.pin.sethigh(led_pin)
tmr.delayms(250)
pio.pin.setlow(led_pin)
tmr.delayms(250)
end
end
-- Start thread
th1 = thread.start(f1)
....
-- Suspend thread
thread.suspend(th1)
....
-- Resume thread
thread.resume(th1)
thread.stop([thread id])
Остановить все потоки или конкретный поток.
Аргументы:
- thread id (идентификатор потока): этот аргумент необязателен. Если он не указан, функция останавливает все потоки, а если указан, останавливает указанный поток. Эта функция останавливает выполнение базового потока операционной системы и удаляет его из памяти.
Возвращает: ничего.
-- Function to execute
f1 = function()
local led_pin = pio.GPIO4
pio.pin.setdir(pio.OUTPUT, led_pin)
while true do
pio.pin.sethigh(led_pin)
tmr.delayms(250)
pio.pin.setlow(led_pin)
tmr.delayms(250)
end
end
-- Start thread
th1 = thread.start(f1)
....
-- Stop thread
thread.stop(th1)
thread.status(thread id)
Получить статус конкретного потока.
Аргументы:
- thread id (идентификатор потока): идентификатор потока.
Возвращает: статус потока (выполняется, приостановлен или nil).
-- Function to execute
f1 = function()
local led_pin = pio.GPIO4
pio.pin.setdir(pio.OUTPUT, led_pin)
while true do
pio.pin.sethigh(led_pin)
tmr.delayms(250)
pio.pin.setlow(led_pin)
tmr.delayms(250)
end
end
-- Start thread
th1 = thread.start(f1)
....
-- Suspend thread
thread.suspend(th1)
-- Get thread status
thread.status(th1)
> suspended
thread.sleep(seconds)
Усыпить текущий поток на указанное количество секунд.
Аргументы:
- seconds (секунды): количество секунд сна.
Возвращает: ничего.
-- Sleep for 4 seconds
thread.sleep(4)
thread.sleepms(milliseconds)
Усыпить текущий поток на указанное количество миллисекунд.
Аргументы:
- milliseconds (миллисекунды): количество миллисекунд сна.
Возвращает: ничего.
-- Sleep for 4 milliseconds
thread.sleepms(4)
thread.sleepus(useconds)
Усыпить текущий поток на указанное количество микросекунд.
Аргументы:
- useconds (микросекунды): количество микросекунд сна.
Возвращает: ничего.
-- Sleep for 500000 micro seconds (0,5 seconds)
thread.sleepus(500000)
Мьютексы
Взаимное исключение (mutex) — это свойство управления параллелизмом, которое устанавливается с целью предотвращения условий гонки; это требование, чтобы один поток исполнения никогда не входил в критическую секцию в то же время, что и другой параллельный поток исполнения.
instance = thread.createmutex([type])
Создает экземпляр мьютекса.
Аргументы:
- type (необязательно): тип мьютекса, может быть либо thread.Lock, либо thread.RecursiveLock. Тип мьютекса по умолчанию — thread.RecursiveLock.
Возвращает: экземпляр мьютекса или исключение. Этот экземпляр необходимо сохранить в переменной для дальнейших операций с ним.
instance:lock()
Блокирует экземпляр мьютекса. Если мьютекс заблокирован другим потоком, вызывающий поток блокируется, пока мьютекс не будет разблокирован.
Аргументы: нет.
Возвращает: ничего.
instance:unlock()
Разблокирует экземпляр мьютекса.
Аргументы: нет.
Возвращает: ничего.
instance:trylock()
Попытка заблокировать мьютекс. Если мьютекс заблокирован другим потоком, эта функция возвращает false, и вызывающий поток не блокируется. Если мьютекс не заблокирован другим потоком, эта функция блокирует мьютекс и возвращает true.
Аргументы: нет.
Возвращает: true, если мьютекс заблокирован вызывающим процессом, или false, если мьютекс заблокирован другими потоками.
Пример взаимного исключения
В следующем примере создаются 4 потока, которые увеличивают глобальную переменную timer 20000 раз каждый. Когда все потоки завершают работу, значение счетчика должно быть 80000.
counter = 0
mtx = thread.createmutex()
thread.start(function()
local i = 0
while (i < 20000) do
mtx:lock()
counter = counter + 1
mtx:unlock()
i = i + 1
end
end)
thread.start(function()
local i = 0
while (i < 20000) do
mtx:lock()
counter = counter + 1
mtx:unlock()
i = i + 1
end
end)
thread.start(function()
local i = 0
while (i < 20000) do
mtx:lock()
counter = counter + 1
mtx:unlock()
i = i + 1
end
end)
thread.start(function()
local i = 0
while (i < 20000) do
mtx:lock()
counter = counter + 1
mtx:unlock()
i = i + 1
end
end)