Thread

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)