Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

임베디드 소프트웨어/Zephyr

[nRF52840 + Zephyr] #8. Thread Management

방피터 2023. 5. 30. 20:32

제퍼에서 thread를 굳이 나누자면
System thread와
User thread로 나눌 수 있어.
System thread는 main()을 호출하는 main thread와 idle thread 그리고 workqueue thread 정도가 될거고

User thread는 말 그대로 유저가 만드는 거겠지.


Thread 뭐 별거 없어.
생성하고 종료하고 멈추고 재시작하고 이게 전부.

이왕 이면 예제를 통해 살펴보는게 좋겠지?

#define MY_STACK_SIZE 500
#define MY_PRIORITY 5

extern void my_entry_point(void *, void *, void *);

K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_thread my_thread_data;

k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
                                 K_THREAD_STACK_SIZEOF(my_stack_area),
                                 my_entry_point,
                                 NULL, NULL, NULL,
                                 MY_PRIORITY, 0, K_NO_WAIT);

이건 제퍼 공식 문서에서 제공하는 예제야.

k_thread_create라는 함수를 이용해서 MY_STACK_SIZE 크기의 메모리를 갖는 thread를 생성하는거지.

그런데 이렇게 하려면 main()안에서 k_thread_create를 호출해야 해.

runtime 전용인거지

👇👇👇

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define MY_STACK_SIZE 500
#define MY_PRIORITY 5

#define LED0_NODE DT_NODELABEL(led0)
#define LED1_NODE DT_NODELABEL(led1)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);
static struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE,gpios);


void my_entry_point(void *, void *, void *){
	int ret;
	ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
	for(;;){
		gpio_pin_toggle_dt(&led1);
		k_sleep(K_MSEC(500));
	}
}

K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_thread my_thread_data;

void main(void)
{
	int ret;
	ret = gpio_pin_configure_dt(&led0,GPIO_OUTPUT);

	k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
                                 K_THREAD_STACK_SIZEOF(my_stack_area),
                                 my_entry_point,
                                 NULL, NULL, NULL,
                                 MY_PRIORITY, 0, K_NO_WAIT);
	for(;;){
		gpio_pin_toggle_dt(&led0);
		k_sleep(K_MSEC(1000));
	}
}

지겨운 LED thread... 어쨌든 돈다.

뭐 이것도 나쁘지 않지만 사실 더 편한 방법이 있어.

런타임이 아니고 컴파일 타임에 thread를 생성할 수 있는 메크로가 제공되거든.

아래는 제퍼 공식 문서 예제

👇👇

#define MY_STACK_SIZE 500
#define MY_PRIORITY 5

extern void my_entry_point(void *, void *, void *);

K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
                my_entry_point, NULL, NULL, NULL,
                MY_PRIORITY, 0, 0);

훨씬 간단하지?

이렇게 하면 main()에서 호출할 필요없이 thread가 생성돼.

👇👇

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define MY_STACK_SIZE 500
#define MY_PRIORITY 5

#define LED0_NODE DT_NODELABEL(led0)
#define LED1_NODE DT_NODELABEL(led1)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);
static struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE,gpios);

void my_entry_point(void *, void *, void *){
	int ret;
	ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
	for(;;){
		gpio_pin_toggle_dt(&led1);
		k_sleep(K_MSEC(300));
	}
}

K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
                my_entry_point, NULL, NULL, NULL,
                MY_PRIORITY, 0, 0);

void main(void)
{
	int ret;
	ret = gpio_pin_configure_dt(&led0,GPIO_OUTPUT);
	for(;;){
		gpio_pin_toggle_dt(&led0);
		k_sleep(K_MSEC(1000));
	}
}

 

처음에 설명했듯이 여기에서 main()을 삭제해도 새로 만든 thread는 동작해.

main()은 그냥 main thread에서 초기화를 마친 후 호출하는 함수에 불과하기 때문.

궁금한 사람들은 한번 해보자.

 

thread를 아예 종료(abort)하는 일은 드물것 같으니 넘어가고 대신

suspend - resume을 해보자고

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define MY_STACK_SIZE 500
#define MY_PRIORITY 5

#define LED0_NODE DT_NODELABEL(led0)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);

void my_entry_point(void *, void *, void *){
	int ret;
	ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
	for(;;){
		gpio_pin_toggle_dt(&led1);
		k_sleep(K_MSEC(50));
	}
}

K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
                my_entry_point, NULL, NULL, NULL,
                MY_PRIORITY, 0, 0);

void main(void)
{
	for(;;){
		k_thread_suspend(my_tid);
		k_sleep(K_MSEC(1000));
		k_thread_resume(my_tid);
		k_sleep(K_MSEC(1000));
	}
}

thread의 일시 정지 - 시작

역시나... 너무 쉽게.. 동작..

딱히 더 할게 생각나지 않는다;;;

아래는 제퍼 thread 상태를 다이어그램으로 나타낸거야.

어떤 상태가 있는지 정도는 알아두자. 그럼 안녕!

제퍼 thread status diagram

 

👉👉 nrf 보드가 52840DK가 아니라 5340DK인데 너무 신경쓰지 말자. 동작은 똑같아 ㅎ

 

2023.06.02 - [임베디드 소프트웨어/Zephyr] - [nRF52840 + Zephyr] #9. Memory Management

 

[nRF52840 + Zephyr] #9. Memory Management

제퍼에서 제공하는 Memory management 기능은 여러 가지가 있는데 k_malloc()과 k_free() 정도만 알면 될 것 같아. 사실 나머지는 어디서 어떻게 사용되는지 잘 모르겠거든 ㅋㅋ 누가 잘 아는 사람은 알려

engschool.tistory.com

 

반응형