# [Legato] Thread > https://docs.legato.io/latest/c_threading.html https://docs.legato.io/latest/le__thread_8h.html ## Legato Thraed 基本使用流程 ![image2024-9-19_15-11-38](https://hackmd.io/_uploads/SygzYcrR0.png) Legato Thread 基本使用流程如上圖所示。 一個 worker thread 有三種可能的原因結束: 1. 從 thread main function return。 2. Worker thread 自己呼叫 `le_thread_Exit()`。 3. 被其他 thread 呼叫 `le_thread_Cancel()` 而結束。 最後,若有其他 thread 呼叫 `le_thread_Join()` 在等該 worker thread 的結果,也要記得把結果傳給該 thread。 ## 注意事項 - 和 POSIX `pthread_create` 不一樣的地方在於,當我們執行 `le_thread_Create` 建立一個 Legato thread 後,Legato thread 並不會馬上執行,而是處在 ++suspend state++。 - 若有需要可以趁這時候設定 Legato thread 的一些 attributes,然後再用 `le_thread_Start` 來啟動該 Legato thread。 - 當 parentThread 建立了另一個 thread - childThread,則只有 parentThread 可以設定 childThread 的 attributes 以及啟動該 childThread,其他 thread 不可以設定該 childThread 的 attributes 或啟動它。 - 我們可以為同一個 thread 註冊多個 destructors,這些 destructor 會以註冊時的反向順序被呼叫(也就是最後註冊的 destructor 會最先被呼叫)。 ## Example 以下例子,示範怎麼傳多個變數到 worker thread,並且將結果回傳給呼叫 `le_thread_Join()` 的 thread 以取得結果。 此外,也為 worker thread 註冊三個 destructor,以及傳送 `context` 至 destructor,並在 destructor 內取得 `context`。 最後,亦觀察 destructor 的呼叫順序是否會依照註冊 destructor 的反向順序呼叫。 ### Project Structure ``` thread ├── threadApp.adef └── threadComp ├── Component.cdef └── thread.c ``` ### `threadApp.adef` ```adef executables: { threadExec = ( threadComp ) } processes: { run: { threadProc = ( threadExec ) } } ``` ### `Component.cdef` ```cdef sources: { thread.c } ``` ### `thread.c` ```cpp #include "legato.h" #include "interfaces.h" #define DESTRUCTOR_NUM (3) #define MSG_BYTE_SIZE ( sizeof(char) * 50 ) static le_thread_Ref_t workerThreadRef = NULL; typedef struct { int32_t n1; int32_t n2; char *str; } MyParameter_t; typedef struct { int32_t sum; char *str; } MyReturnValue_t; void threadDestructor1(void *context) { LE_INFO("[%s] %s", le_thread_GetMyName(), (char *) context); free(context); } void threadDestructor2(void *context) { LE_INFO("[%s] %s", le_thread_GetMyName(), (char *) context); free(context); } void threadDestructor3(void *context) { LE_INFO("[%s] %s", le_thread_GetMyName(), (char *) context); free(context); } void (*threadDestructorFuncs[]) (void *) = { threadDestructor1, threadDestructor2, threadDestructor3 }; void *workerThreadFunc(void *context) { char *destructorMsg[DESTRUCTOR_NUM] = {NULL}; for (int i = 0; i < DESTRUCTOR_NUM; ++i) { destructorMsg[i] = (char *) malloc(MSG_BYTE_SIZE); snprintf(destructorMsg[i], MSG_BYTE_SIZE, "inside worker thread DESTRUCTOR %d", (i + 1)); le_thread_AddDestructor(threadDestructorFuncs[i], destructorMsg[i]); } MyParameter_t *paramPtr = (MyParameter_t *) context; paramPtr->str = "WorkerThread says Hello!"; MyReturnValue_t *retPtr = (MyReturnValue_t *) malloc(sizeof(MyReturnValue_t)); retPtr->sum = (paramPtr->n1 + paramPtr->n2); retPtr->str = paramPtr->str; LE_INFO("[%s] retPtr->sum: %d, retPtr->str: %s", le_thread_GetMyName(), retPtr->sum, retPtr->str); return (void *) retPtr; } COMPONENT_INIT { MyParameter_t my_param = {.n1 = 100, .n2 = 200, .str = NULL}; LE_INFO("[%s] my_param - n1: %d, n2: %d, str: %s", le_thread_GetMyName(), my_param.n1, my_param.n2, ( (my_param.str == NULL) ? "NULL" : my_param.str) ); workerThreadRef = le_thread_Create("MyWorkerThread", workerThreadFunc, (void *) &my_param); le_thread_SetJoinable(workerThreadRef); le_thread_Start(workerThreadRef); MyReturnValue_t *res = NULL; le_thread_Join(workerThreadRef, (void **) &res); LE_INFO("[%s] result - sum: %d, str: %s", le_thread_GetMyName(), res->sum, res->str); free(res); } ``` ### Result ![image](https://hackmd.io/_uploads/S1kss9BRA.png) 以上的程式碼,讓 worker thread 先註冊了 destructor1,之後才註冊 destructor2,最後註冊 destructor3。 從執行結果可看到,當該 worker thread 要結束時,確實先呼叫了 destructor3,然後 destructor2,最後才呼叫 destructor1。