1@page page_thread_management Thread Management
2
3When we are facing a big task in our daily life, we usually break it down into a number of simple, easy-to-manage smaller tasks. Then, we would deal with these smaller tasks one by one, gradually, the big task is worked out. In a multi-threaded operating system, developers also need to break down a complex application into multiple small, schedulable, and serialized program units. When tasks are reasonably divided and properly executed, this design allows the system to meet the capacity and time requirements of the real-time system. For example, to have the embedded system to perform such tasks, the system would collect data through sensors and display the data on the screen. In a multi-threaded real-time system, the task can be decomposed into two subtasks. The subtask, as shown in the following figure, reads the sensor data continuously and writes the data into the shared memory. The other subtask periodically reads the data from the shared memory and outputs the sensor data onto the screen.
4
5![Switching Execution of Sensor's Data Receiving Task and Display Task](figures/04Task_switching.png)
6
7In RT-Thread, the application entity corresponding to the above subtask is the thread. The thread is the carrier of the task. It is the most basic scheduling unit in RT-Thread. It describes the running environment of a task execution. It also describes the priority level of the task - an important task can be set a relatively high priority, while a non-important task can be set a lower priority, and different tasks can also be set to the same priority and take turns while running.
8
9When a thread runs, it thinks it is has sole access to the CPU as it is running. The runtime environment when the thread executes is called the context, specifically each variables and data, including all register variables, stacks, memory information, and so on.
10
11This chapter will be divided into five sections to introduce thread management in RT-Thread. After reading this chapter, readers will have a deeper understanding of the thread management mechanism of RT-Thread. They will have clear answers to questions like what states does a thread have, how to create a thread, why do idle threads exist, etc.
12
13# Thread Management Features
14
15The main function of RT-Thread's thread management is to manage and schedule threads. There are two types of threads in the system, namely system threads and user threads. System threads are threads created by the RT-Thread kernel. User threads are the thread created by the application. Both types of threads will allocate thread objects from the kernel object container. When a thread is deleted, it will also be deleted from the object container. As shown in the following figure, each thread has important attributes, such as a thread control block, thread stack, entry function, and so on.
16
17![Object Container and Thread Object ](figures/04Object_container.png)
18
19The thread scheduler of RT-Thread is preemptive and its main job is to find the highest priority thread from the list of ready threads so as to ensure that the highest priority thread can be run. Once the highest priority task is ready, it can always get the CPU usage it needs.
20
21When a running thread makes the running condition ready for another thread with a higher priority, then the current running thread's CPU usage right is deprived, or in other words, released, and the high-priority thread immediately gets CPU access.
22
23If it is the interrupt service routine that makes the running condition ready for the thread with a higher priority, when the interrupt is completed, the interrupted thread is suspended, the thread with the higher priority starts running.
24
25When the scheduler schedules threads and switches them, the current thread context is first saved. When it is switched back to this thread, the scheduler restores the context information of the thread.
26
27# Working Mechanism of Thread
28
29## Thread Control Block
30
31In RT-Thread, the thread control block is represented by structure `struct rt_thread`, which is a data structure used by the operating system to manage threads. It stores information about the thread, such as priority, thread name, thread status, etc. It also includes a linked list structure for connecting threads, event collection of thread waiting, etc., which is defined as follows:
32
33```c
34/* Thread Control Block */
35struct rt_thread
36{
37    /* rt Object */
38    char        name[RT_NAME_MAX];      /* Thread Name */
39    rt_uint8_t  type;                   /* Object Type */
40    rt_uint8_t  flags;                  /* Flag Position */
41
42    rt_list_t   list;                   /* Object List */
43    rt_list_t   tlist;                  /* Thread List */
44
45    /* Stack Pointer and Entry pointer */
46    void       *sp;                      /* Stack Pointer */
47    void       *entry;                   /* Entry Function Pointer */
48    void       *parameter;               /* Parameter */
49    void       *stack_addr;              /* Stack Address Pointer */
50    rt_uint32_t stack_size;              /* Stack Size */
51
52    /* Error Code */
53    rt_err_t    error;                   /* Thread Error Code */
54    rt_uint8_t  stat;                    /* Thread State */
55
56    /* Priority */
57    rt_uint8_t  current_priority;        /* Current Priority */
58    rt_uint8_t  init_priority;           /* Initial Priority */
59    rt_uint32_t number_mask;
60
61    ......
62
63    rt_ubase_t  init_tick;                /* Thread Initialization Count Value */
64    rt_ubase_t  remaining_tick;           /* Thread Remaining Count Value */
65
66    struct rt_timer thread_timer;               /* Built-in Thread Timer */
67
68    void (*cleanup)(struct rt_thread *tid);     /* Thread Exit Clear Function */
69    rt_uint32_t user_data;                      /* User Data */
70};
71```
72
73`init_priority` is the thread priority specified when the thread was created, and will not be changed while the thread is running (unless the user executes the thread control function to manually adjust the thread priority). `cleanup` will be called back by the idle thread when the thread exits to perform the user-setup cleanup site and so on. The last member, `user_data`, can be used by the user to send some data into the thread control block to provide an implementation similar to thread private data.
74
75## Thread Important Attributes
76
77### Thread Stack
78
79RT-Thread's threads have a dependent stack. When the thread is switched, the context of the current thread is stored in the stack. When the thread is about to resume operation, the context information is read from the stack and recovered.
80
81The thread stack is also used to store local variables in functions: local variables in functions are applied from the thread stack space; local variables in functions are initially allocated from registers (ARM architecture), when this function calls another function, these local variables will be placed on the stack.
82
83For the first run of thread, the context can be constructed manually to set initial environment like: entry function (PC register), entry parameter (R0 register), return position (LR register), current machine operating status (CPSR register).
84
85The growth direction of the thread stack is closely related to the CPU architecture. Versions before RT-Thread 3.1.0 only allow the stack to grow from high address to low address. For the ARM Cortex-M architecture, the thread stack can be constructed as shown below.
86
87![Thread Stack](figures/04thread_stack.png)
88
89When setting the size for thread stack, a larger thread stack can be designed for an MCU with a relatively large resource pool; or a larger stack can be set initially, for example, a size of 1K or 2K bytes, then in FinSH, use `list_thread` command to check the size of the stack used by the thread during the running of the thread. With this command, you can see the maximum stack depth used by the thread from the start of the thread to the current point in time, and then add the appropriate margin to form the final thread stack size, and finally modify the size of the stack space.
90
91### Thread State
92
93Only one thread is allowed to run on a processor at any time. Apart from the running process, threads have various different operating states, such as initial state, suspended state, ready state, etc. In RT-Thread, a thread can have five states, and the operating system would automatically adjust its state based on its running condition.
94
95The five states of a thread in RT-Thread are shown in the following table:
96
97| **States**      | **Description**                                              |
98| --------------- | ------------------------------------------------------------ |
99| Initial State   | Thread is in initial state when it has just been created but has not started running; in initial state, the thread does not participate in scheduling. In RT-Thread, the macro definition of this state is RT_THREAD_INIT |
100| Ready State     | In ready state, the thread is queued according to priority, waiting to be executed; the processor is available again once the current thread is finished, and the operating system will then immediately find the ready thread with the highest priority to run. In RT-Thread, the macro definition of this state is RT_THREAD_READY |
101| Running State   | Thread is currently running. In a single-core system, only the thread returned from the rt_thread_self() function is running; in a multi-core system, more than one thread may be running. In RT-Thread, the macro definition of this state is RT_THREAD_RUNNING |
102| Suspended State | Also known as the blocking state. It may be suspended and paused because the resource is unavailable, or the thread is suspended because it is voluntarily delayed. In suspended state, threads do not participate in scheduling. In RT-Thread, the macro definition of this state is RT_THREAD_SUSPEND |
103| Closed State    | It will be turned to closed state when the thread finishes running. The thread in closed state does not participate in the thread's scheduling. In RT-Thread, the macro definition of this state is RT_THREAD_CLOSE |
104
105### Thread Priority
106
107The priority of the RT-Thread thread indicates the thread's priority of being scheduled. Each thread has its priority. The more important the thread, the higher priority it should be given, resulting in a higher chance of being scheduled.
108
109RT-Thread supports a maximum of 256 thread priorities (0~255). The lower the number, the higher the priority, with 0 being the highest priority. In some systems with tight resources, you can choose system configurations that only support 8 or 32 priorities according to the actual situation; for the ARM Cortex-M series, 32 priorities are commonly used. The lowest priority is assigned to idle threads by default and is not used by users. In the system, when a thread with a higher priority is ready, the current thread with the lower priority will be swapped out immediately, and the high-priority thread will preempt the processor.
110
111### Time Slice
112
113Each thread has a time slice parameter, but time slice is only valid for ready-state threads of the same priority. The system schedules the ready-state threads with the same priority using time slice rotation scheduling method. In this case, time slice plays the role of constraining thread's single running time and the unit is a system tick (OS Tick). Suppose there are 2 ready-state threads, A and B with the same priority. Time slice of A thread is set to 10, and time slice of B thread is set to 5. When there is no ready-state thread with higher priority than A in the system, the system will switch back and forth between thread A and B. Each time the system performs 10 OS Ticks on thread A, and 5 OS Ticks on thread B, as shown below.
114
115![Same Priority Time Slice Round Robin](figures/04time_slience.png)
116
117### Thread Entry Function
118
119"Entry" in Thread Control Block is the thread's entry function, which is the thread's main function. The thread's entry function is created by the user. There are generally two forms of code:
120
121**Infinite Loop Mode**:
122
123In real-time systems, threads are usually passive: this is determined by the characteristics of real-time systems, which usually wait for external events to occur, and then perform the appropriate services:
124
125```c
126void thread_entry(void* parameter)
127{
128    while (1)
129    {
130    /* Wait for an event to occur */
131
132    /* Serve and process events */
133    }
134}
135```
136
137It may seem that threads have no restrictions on program execution and that all operations can be performed. But as a real-time system, with clear priorities, if a program in a thread is stuck in an infinite loop, then threads with a lower priorities will not be executed. Therefore, one thing that must be noted in the real-time operating system is that the thread cannot be stuck in an infinite loop operation, and there must be an action to relinquish the use of the CPU, such as calling a delay function in the loop or actively suspending. The purpose of user designing a infinite loop thread is to let this thread be continuously scheduled and run by the system and never be deleted.
138
139**Sequential Execution or Finite-Cycle Mode**:
140
141With simple sequential statements, such as `while()` or `for()` loop, etc., these threads will not cycle or permanently loop. They can be described as a "one-off" threads and will surely be executed. After it finished executing, the thread will be automatically deleted by the system.
142
143```c
144static void thread_entry(void* parameter)
145{
146    /* Processing Transaction #1 */
147148    /* Processing Transaction #2 */
149150    /* Processing Transaction #3 */
151}
152```
153
154### Thread Error Code
155
156Each thread is one execution scenario. Error codes are closely related to the execution environment, so each thread is equipped with a variable to store the error code. These error codes are as follows:
157
158```c
159#define RT_EOK           0 /* No error     */
160#define RT_ERROR         1 /* Regular error     */
161#define RT_ETIMEOUT      2 /* Timeout error     */
162#define RT_EFULL         3 /* Resource is full     */
163#define RT_EEMPTY        4 /* No resource     */
164#define RT_ENOMEM        5 /* No memory     */
165#define RT_ENOSYS        6 /* System does not support     */
166#define RT_EBUSY         7 /* System busy     */
167#define RT_EIO           8 /* IO error       */
168#define RT_EINTR         9 /* Interrupt system call   */
169#define RT_EINVAL       10 /* Invalid Parameter      */
170```
171
172## Switching Thread State
173
174RT-Thread provides a set of operating system call interfaces that make the state of a thread to switch back and forth between these five states. The conversion relationship between these states is shown in the following figure:
175
176![Thread State Switching Diagram](figures/04thread_sta.png)
177
178Threads enter the initial state (RT_THREAD_INIT) by calling the functions `rt_thread_create()` or `rt_thread_init()`; threads in the initial state enter the ready state (RT_THREAD_READY) by calling the function `rt_thread_startup()`; threads in the ready state are scheduled by the scheduler and enter the running state (RT_THREAD_RUNNING). When a running thread calls a function such as `rt_thread_delay()`, `rt_sem_take()`, `rt_mutex_take()`, `rt_mb_recv()` or fails to get resources, it will enter the suspended state (RT_THREAD_SUSPEND); if a thread in suspended state waits until timeout and still doesn't acquire the resources, or other threads release the resources, it will return to the ready state.
179
180If a thread in suspended state calls the functions `rt_thread_delete()` or `rt_thread_detach()`, it will switch to the closed state (RT_THREAD_CLOSE); as for thread in the running state, if the operation is completed, the function `rt_thread_exit()` will be executed at the last part of the thread to change its state into the closed state.
181
182>In RT-Thread, a thread does not actually have a running state; the ready state and the running state are equivalent.
183
184## System thread
185
186As mentioned previously, system threads refers to threads created by the system and user threads are threads created by the user program calling the thread management interface. System threads In RT-Thread kernel include the idle thread and the main thread.
187
188### Idle Thread
189
190An idle thread is the lowest priority thread created by the system, and its thread state is always ready. When no other ready thread exists in the system, the scheduler will schedule the idle thread, which is usually an infinite loop and can never be suspended. In addition, idle threads have special functions in RT-Thread:
191
192If a thread finishes running, the system will automatically delete the thread by executing the function `rt_thread_exit()`, first removing the thread from the system ready queue, then changing the state of the thread to the closed state which means it no longer participates in system scheduling, and then suspend it into the `rt_thread_defunct` queue (a thread queue that is not reclaimed and in a closed state). Lastly, the idle thread reclaims the resources of the deleted thread.
193
194The idle thread also provides an interface to run a hook function set by the user. The hook function is called when idle thread is running, which is suitable for operations like hooking into power management, watchdog feeding, etc.
195
196### Main Thread
197
198When the system starts, it will create the main thread. Its entry function is `main_thread_entry()`. User's application entry function `main()` starts from here. After the system scheduler starts, the main thread starts running. The process is as follows. Users can add their own application initialization code to the `main()` function.
199
200![Main Thread Calling Process](figures/04main_thread.png)
201
202# Thread Management
203
204The first two sections of this chapter conceptually explain the function and working mechanism of threads. This section will delve into the various interfaces of threads and give some source code to help the reader understand threads.
205
206The following figure depicts related operations to threads, including creating / initializing threads, starting threads, running threads, deleting / detaching threads. You can use `rt_thread_create()` to create a dynamic thread and `rt_thread_init()` to initialize a static thread. The difference between a dynamic thread and a static thread is that for a dynamic thread, the system automatically allocates stack space and thread handles from the dynamic memory heap (only after initializing the heap can the system create a dynamic thread). As for static threads, it is the user that allocates the stack space and the thread handle.
207
208![Thread Related Operations](figures/04thread_ops.png)
209
210## Create and Delete Thread
211
212To become an executable object, a thread must be created by the kernel of the operating system. You can create a dynamic thread through the following interface:
213
214```c
215rt_thread_t rt_thread_create(const char* name,
216                            void (*entry)(void* parameter),
217                            void* parameter,
218                            rt_uint32_t stack_size,
219                            rt_uint8_t priority,
220                            rt_uint32_t tick);
221```
222
223When this function is called, the system will allocate a thread handle from the dynamic heap memory and allocate the corresponding space from the dynamic heap memory according to the stack size specified in the parameter. The allocated stack space is aligned in RT_ALIGN_SIZE mode configured in rtconfig.h. The parameters and return values of the thread creation `rt_thread_create()` are as follows:
224
225|Parameters  |Description                             |
226|------------|----------------------------------------------------------------------------------------|
227| name       | The name of the thread; the maximum length of the thread name is specified by macro RT_NAME_MAX in rtconfig.h, and the extra part is automatically truncated. |
228| entry      | Thread entry function. |
229| parameter  | Thread entry function's parameter.           |
230| stack_size | Thread stack size in bytes.                       |
231| priority   | Priority of the thread. The priority range is based on the system configuration (macro definition RT_THREAD_PRIORITY_MAX in rtconfig.h). If 256-level priority is supported, then the range is from 0 to 255. The smaller the value, the higher the priority, and 0 is the highest priority. |
232| tick       | The time slice size of the thread. The unit of the time slice (tick) is the tick of the operating system. When there are threads with the same priority in the system, this parameter specifies the maximum length of time of a thread for one schedule. At the end of this time slice run, the scheduler automatically selects the next ready state of the same priority thread to run. |
233|**Return**  | ——                                                                                           |
234| thread     | Thread creation succeeds, return thread handle.                   |
235| RT_NULL    | Failed to create thread.                                    |
236
237For some threads created with `rt_thread_create()`, when not needed or when an error occurs, one can use the following function interface to completely remove the thread from the system:
238
239```c
240rt_err_t rt_thread_delete(rt_thread_t thread);
241```
242
243After calling this function, the thread object will be moved out of the thread list and removed from the kernel object manager. Consequently, the stack space occupied by the thread will also be freed, and the reclaimed space will be reused for other memory allocations. In fact, using the `rt_thread_delete()` function to delete the thread interface is just changing the corresponding thread state to RT_THREAD_CLOSE state and then putting it into rt_thread_defunct queue; the actual delete action (releasing the thread control block and releasing the thread stack) needs to be completed later by an idle thread when it is being executed.
244
245The parameters and return values of thread deleting `rt_thread_delete()` interface are shown in the following table:
246
247|**Parameter**  |**Description**        |
248|------------|------------------|
249| thread     | Thread handles to delete |
250|**Return**  | ——               |
251| RT_EOK     | Delete thread successfully. |
252| \-RT_ERROR | Failed to delete thread. |
253
254This function is only valid when the system dynamic heap is enabled (meaning RT_USING_HEAP macro definition is already defined).
255
256## Initialize and Detach Thread
257
258The initialization of a thread can be done using the following function interface, to initialize a static thread object:
259
260```c
261rt_err_t rt_thread_init(struct rt_thread* thread,
262                        const char* name,
263                        void (*entry)(void* parameter), void* parameter,
264                        void* stack_start, rt_uint32_t stack_size,
265                        rt_uint8_t priority, rt_uint32_t tick);
266```
267
268The thread handle of the static thread (in other words, the thread control block pointer) and the thread stack are provided by the user. A static thread means that the thread control block and the thread running stack are generally set to global variables, which are determined and allocated when compiling. The kernel is not responsible for dynamically allocating memory space. It should be noted that the user-provided stack starting address needs to be system aligned (for example, 4-byte alignment is required on ARM). The parameters and return values of the thread initialization interface `rt_thread_init()` are as follows:
269
270|**Parameter**   |**Description**                                                                                                                                                                                                        |
271|-----------------|---------------------------------------------------------------------------|
272| thread      | Thread handle. Thread handle is provided by the user and points to the corresponding thread control block memory address.                    |
273| name        | Name of the thread; the maximum length of the thread name is specified by the RT_NAME_MAX macro defined in rtconfig.h, and the extra part is automatically truncated. |
274| entry       | Thread entry function.                                                                                                                                                                              |
275| parameter   | Thread entry function parameter.                                                                                                                                                                |
276| stack_start | Thread stack start address                                                                                                                                                                     |
277| stack_size  | Thread stack size in bytes. Stack space address alignment is required in most systems (for example, alignment to 4-byte addresses in the ARM architecture) |
278| priority    | The priority of the thread. The priority range is based on the system configuration (macro definition RT_THREAD_PRIORITY_MAX in rtconfig.h). If 256 levels of priority are supported, the range is from 0 to 255. The smaller the value, the higher the priority, and 0 is the highest priority. |
279| tick        | The time slice size of the thread. The unit of the time slice (tick) is the tick of the operating system. The unit of the time slice (tick) is the tick of the operating system. When there are threads with the same priority in the system, this parameter specifies the maximum length of time of a thread for one schedule. At the end of this time slice run, the scheduler automatically selects the next ready state of the same priority thread to run. |
280|**Return**   | ——      |
281| RT_EOK      | Thread creation succeeds. |
282| \-RT_ERROR  | Failed to create thread. |
283
284For threads initialized with `rt_thread_init()`, using `rt_thread_detach()` will cause the thread object to be detached from the thread queue and kernel object manager. The detach thread function is as follows:
285
286```c
287rt_err_t rt_thread_detach (rt_thread_t thread);
288```
289
290Parameters and return values of the thread detached from the interface `rt_thread_detach()` are as follows:
291
292|**Parameters**  |**Description**                                                  |
293|------------|------------------------------------------------------------|
294| thread     | Thread handle, which should be the thread handle initialized by rt_thread_init. |
295|**Return**  | ——                                                         |
296| RT_EOK     | Thread detached successfully.                  |
297| \-RT_ERROR | Thread detachment failed.                      |
298
299This function interface corresponds to the `rt_thread_delete()` function. The object operated by the rt_thread_delete() function is the handle created by rt_thread_create(), and the object operated by the rt_thread_detach() function is the thread control block initialized with the rt_thread_init() function. Again, the thread itself should not call this interface to detach thread itself.
300
301## Start Thread
302
303The thread created (initialized) is in initial state and does not enter the scheduling queue of the ready thread. We can call the following function interface to make the thread enter the ready state after the thread is initialized/created successfully:
304
305```c
306rt_err_t rt_thread_startup(rt_thread_t thread);
307```
308
309When this function is called, the state of the thread is changed to the ready state and placed in the corresponding priority queue for scheduling. If the newly started thread has a higher priority than the current thread, it will immediately switch to the new thread. The parameters and return values of the thread start interface `rt_thread_startup()` are as follows:
310
311|**Parameter**  |**Description**    |
312|------------|--------------|
313| thread     | Thread handle. |
314|**Return**  | ——           |
315| RT_EOK     | Thread started successfully. |
316| \-RT_ERROR | Thread start failed. |
317
318## Obtaining Current Thread
319
320During the running of the program, the same piece of code may be executed by multiple threads. At the time of execution, the currently executed thread handle can be obtained through the following function interface:
321
322```c
323rt_thread_t rt_thread_self(void);
324```
325
326The return value of this interface is shown in the following table:
327
328|**Return**|**Description**            |
329|----------|----------------------|
330| thread   | The currently running thread handle. |
331| RT_NULL  | Failed, the scheduler has not started yet. |
332
333## Making Thread Release Processor Resources
334
335When the current thread's time slice runs out or the thread actively requests to release the processor resource, it will no longer occupy the processor, and the scheduler will select the next thread of the same priority to execute. After the thread calls this interface, the thread is still in the ready queue. The thread gives up the processor using the following function interface:
336
337```c
338rt_err_t rt_thread_yield(void);
339```
340
341After calling this function, the current thread first removes itself from its ready priority thread queue, then suspends itself to the end of the priority queue list, and then activates the scheduler for thread context switching (if there is no other thread with the same priority, then this thread continues to execute without context switching action).
342
343The `rt_thread_yield()` function is similar to the `rt_schedule()` function, but the behavior of the system is completely different when other ready-state threads of the same priority exist. After executing the `rt_thread_yield()` function, the current thread is swapped out and the next ready thread of the same priority will be executed. After the `rt_schedule()` function is executed, the current thread is not necessarily swapped out. Even if it is swapped out, it will not be placed at the end of the ready thread list. Instead, the thread with the highest priority is selected in the system and executed. If there is no thread in the system with a higher priority than the current thread, the system will continue to execute the current thread after the `rt_schedule()` function is executed.
344
345## Thread Sleep
346
347In practical applications, we sometimes need to delay the current thread running for a period of time and re-run at a specified time. This is called "thread sleep". Thread sleep can use the following three function interfaces:
348
349```c
350rt_err_t rt_thread_delay(rt_tick_t tick);
351rt_err_t rt_thread_mdelay(rt_int32_t ms);
352```
353
354These three function interfaces have the same effect. Calling them can cause the current thread to suspend for a specified period of time. After, the thread will wake up and enter the ready state again. This function accepts a parameter that specifies the sleep time of the thread. The parameters and return values of the thread sleep interface rt_thread_delay/mdelay() are as follows:
355
356|**Parameters**|Description                                                    |
357| -------- | ------------------------------------------------------------ |
358| tick/ms  | Thread sleep time:<br>The input parameter tick of rt_thread_delay is in units of 1 OS Tick; <br>The input parameter ms of rt_thread_mdelay is in units of 1ms; |
359|**Return**| ——                                                           |
360| RT_EOK   | Successful operation.                                |
361
362## Suspend and Resume Thread
363
364When a thread calls `rt_thread_delay()`, the thread will voluntarily suspend; when a function such as `rt_sem_take()`, `rt_mb_recv()` is called, the resource is not available for use and will cause the thread to suspend. A thread in a suspended state, if it waits for resources longer than the set time, then the thread will no longer wait for these resources and will return to the ready state; or, when other threads release the resource the thread is waiting for, the thread will also return to the ready state.
365
366The thread suspends using the following function interface:
367
368```c
369rt_err_t rt_thread_suspend (rt_thread_t thread);
370```
371
372The parameters and return values of the thread suspend interface `rt_thread_suspend()` are shown in the following table:
373
374|**Parameters**  |Description                                    |
375|------------|----------------------------------------------|
376| thread     | Thread handle.                       |
377|**Return**  | ——                                           |
378| RT_EOK     | Thread suspends successfully  |
379| \-RT_ERROR | Thread suspension failed because the thread is not in ready state. |
380
381>Generally, you should not use this function to suspend the thread itself, if you really need to use rt_thread_suspend() to suspend the current task, immediately after calling function rt_thread_suspend(),  rt_schedule() needs to be called.
382
383   Functions' context switch is achieved manually. User only needs to understand the role of the interface, which is not recommended.
384
385To resume a thread is to let the suspended thread re-enter the ready state and put the thread into the system's ready queue. Thread resuming uses the following function interface:
386
387```c
388rt_err_t rt_thread_resume (rt_thread_t thread);
389```
390
391The parameters and return values of the thread recovery interface `rt_thread_resume()` are as follows:
392
393|Parameter  |**Description**                                                     |
394|------------|---------------------------------------------------------------|
395| thread     | Thread handle.                                        |
396|**Return**  | ——                                                            |
397| RT_EOK     | Thread resumed successfully.                  |
398| \-RT_ERROR | Thread recovery failed because the state of the thread is not RT_THREAD_SUSPEND state |
399
400## Control Thread
401
402When you need other control over a thread, such as dynamically changing the priority of a thread, you can call the following function interface:
403
404```c
405rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);
406```
407
408The parameters and return values of the thread control interface rt_thread_control() are as follows:
409
410|Function Parameters|**Description**    |
411|--------------|--------------|
412| thread       | Thread handle. |
413| cmd          | Control command demand. |
414| arg          | Control parameter. |
415|**Return**    | ——           |
416| RT_EOK       | Control execution is correct. |
417| \-RT_ERROR   | Failure. |
418
419Demands supported by control command demand cmd include:
420
421•RT_THREAD_CTRL_CHANGE_PRIORITY:dynamically change the priority of a thread;
422
423•RT_THREAD_CTRL_STARTUP:Start running a thread, equivalent to the `rt_thread_startup()` function call;
424
425•RT_THREAD_CTRL_CLOSE:Close a thread, equivalent to the `rt_thread_delete()` function call.
426
427## Set and Delete Idle Hooks
428
429The idle hook function is a hook function of the idle thread. If the idle hook function is set, the idle hook function can be automatically executed to perform other things, such as the LED of system indicator , when the system executes the idle thread. The interface for setting/deleting idle hooks is as follows:
430
431```c
432rt_err_t rt_thread_idle_sethook(void (*hook)(void));
433rt_err_t rt_thread_idle_delhook(void (*hook)(void));
434```
435
436Input parameters and return values of setting idle hook function `rt_thread_idle_sethook()` are as shown in the following table:
437
438|**Function Parameters**|Description      |
439|--------------|----------------|
440| hook         | Set hook function. |
441|**Return**    | ——             |
442| RT_EOK       | Set Successfully. |
443| \-RT_EFULL   | Set fail. |
444
445Input parameters and return values of deleting the idle hook function `rt_thread_idle_delhook()` are as shown in the following table:
446
447|Function Parameters|Description      |
448|--------------|----------------|
449| hook         | Deleted hook function. |
450|**Return**    | ——             |
451| RT_EOK       | Successfully deleted. |
452| \-RT_ENOSYS  | Failed to delete. |
453
454>An idle thread is a thread whose state is always ready. Therefore, hook function must ensure that idle threads will not be suspended at any time. Functions like rt_thread_delay(), rt_sem_take(), etc can't be used because they may cause the thread to suspend.
455
456## Set the Scheduler Hook
457
458During the time when the system is running, it is in the process of thread running, interrupt triggering, responding to interrupts, switching to other threads, and switching between threads. In other words, context switching is the most common event in the system. Sometimes the user may want to know what kind of thread switch has occurred at times, you can set a corresponding hook function by calling the following function interface. This hook function will be called when the system thread switches:
459
460```c
461void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to));
462```
463
464Input parameters for setting the scheduler hook function are shown in the following table:
465
466|**Function Parameters**|Description                  |
467|--------------|----------------------------|
468| hook         | Represents a user-defined hook function pointer |
469
470Hook function `hook()` is declared as follows:
471
472```c
473void hook(struct rt_thread* from, struct rt_thread* to);
474```
475
476Input parameters for the scheduler hook function hook() are shown in the following table:
477
478|Function Parameters|**Description**                          |
479|--------------|------------------------------------|
480| from         | Indicates the thread control block pointer that the system wants to switch out |
481| to           | Indicates the thread control block pointer that the system wants to switch out |
482
483>Please carefully compile your hook function, any carelessness is likely to cause the entire system to run abnormally (in this hook function, it is basically not allowed to call the system API, and should not cause the current running context to suspend).
484
485# Thread Application Sample
486
487An application example in Keil simulator environment is given below.
488
489## Create Thread Sample
490
491This sample is creating a dynamic thread and initializing a static thread. A thread is automatically deleted by the system after it has finished running. The other thread is always printing the counts, as follows:
492
493```c
494#include <rtthread.h>
495
496#define THREAD_PRIORITY         25
497#define THREAD_STACK_SIZE       512
498#define THREAD_TIMESLICE        5
499
500static rt_thread_t tid1 = RT_NULL;
501
502/* Entry Function for Thread 1 */
503static void thread1_entry(void *parameter)
504{
505    rt_uint32_t count = 0;
506
507    while (1)
508    {
509        /* Thread 1 runs with low priority and prints the count value all the time */
510        rt_kprintf("thread1 count: %d\n", count ++);
511        rt_thread_mdelay(500);
512    }
513}
514
515ALIGN(RT_ALIGN_SIZE)
516static char thread2_stack[1024];
517static struct rt_thread thread2;
518/* Entry for Thread 2 */
519static void thread2_entry(void *param)
520{
521    rt_uint32_t count = 0;
522
523    /* Thread 2 has a higher priority to preempt thread 1 and get executed */
524    for (count = 0; count < 10 ; count++)
525    {
526        /* Thread 2 prints count value */
527        rt_kprintf("thread2 count: %d\n", count);
528    }
529    rt_kprintf("thread2 exit\n");
530    /* Thread 2 will also be automatically detached from the system after it finishes running. */
531}
532
533/* Thread Sample */
534int thread_sample(void)
535{
536    /* Creat thread 1, Name is thread1,Entry is thread1_entry */
537    tid1 = rt_thread_create("thread1",
538                            thread1_entry, RT_NULL,
539                            THREAD_STACK_SIZE,
540                            THREAD_PRIORITY, THREAD_TIMESLICE);
541
542    /* Start this thread if you get the thread control block */
543    if (tid1 != RT_NULL)
544        rt_thread_startup(tid1);
545
546    /* Creat thread 2, Name is thread2,Entry is thread2_entry */
547    rt_thread_init(&thread2,
548                   "thread2",
549                   thread2_entry,
550                   RT_NULL,
551                   &thread2_stack[0],
552                   sizeof(thread2_stack),
553                   THREAD_PRIORITY - 1, THREAD_TIMESLICE);
554    rt_thread_startup(&thread2);
555
556    return 0;
557}
558
559/* Export to msh command list */
560MSH_CMD_EXPORT(thread_sample, thread sample);
561```
562
563The simulation results are as follows:
564
565```
566\ | /
567- RT -     Thread Operating System
568 / | \     3.1.0 build Aug 24 2018
569 2006 - 2018 Copyright by rt-thread team
570msh >thread_sample
571msh >thread2 count: 0
572thread2 count: 1
573thread2 count: 2
574thread2 count: 3
575thread2 count: 4
576thread2 count: 5
577thread2 count: 6
578thread2 count: 7
579thread2 count: 8
580thread2 count: 9
581thread2 exit
582thread1 count: 0
583thread1 count: 1
584thread1 count: 2
585thread1 count: 3
586587```
588
589When thread 2 counts to a certain value, it will stop running. Then thread 2 is automatically deleted by the system, and therefore the counting stops. Thread 1 prints the count all the time.
590
591>About deleting threads: Most threads are executed cyclically without needing to be deleted. For thread that can finish running, RT-Thread automatically deletes the thread after the thread finishes running, and deletes it in rt_thread_exit(). User only needs to understand the role of the interface. It is not recommended to use this interface (this interface can be called by other threads or call this interface in the timer timeout function to delete a thread which is not used very often).
592
593## Thread Time Slice Round-Robin Scheduling Sample
594
595This sample is creating two threads that will always print counts when executing, as follows:
596
597```c
598#include <rtthread.h>
599
600#define THREAD_STACK_SIZE   1024
601#define THREAD_PRIORITY     20
602#define THREAD_TIMESLICE    10
603
604/* Thread Entry */
605static void thread_entry(void* parameter)
606{
607    rt_uint32_t value;
608    rt_uint32_t count = 0;
609
610    value = (rt_uint32_t)parameter;
611    while (1)
612    {
613        if(0 == (count % 5))
614        {
615            rt_kprintf("thread %d is running ,thread %d count = %d\n", value , value , count);
616
617            if(count> 200)
618                return;
619        }
620         count++;
621     }
622}
623
624int timeslice_sample(void)
625{
626    rt_thread_t tid = RT_NULL;
627    /* Create Thread 1 */
628    tid = rt_thread_create("thread1",
629                            thread_entry, (void*)1,
630                            THREAD_STACK_SIZE,
631                            THREAD_PRIORITY, THREAD_TIMESLICE);
632    if (tid != RT_NULL)
633        rt_thread_startup(tid);
634
635
636    /* Create Thread 2 */
637    tid = rt_thread_create("thread2",
638                            thread_entry, (void*)2,
639                            THREAD_STACK_SIZE,
640                            THREAD_PRIORITY, THREAD_TIMESLICE-5);
641    if (tid != RT_NULL)
642        rt_thread_startup(tid);
643    return 0;
644}
645
646/* Export to msh command list */
647MSH_CMD_EXPORT(timeslice_sample, timeslice sample);
648```
649
650The simulation results are as follows:
651
652```
653 \ | /
654- RT -     Thread Operating System
655 / | \     3.1.0 build Aug 27 2018
656 2006 - 2018 Copyright by rt-thread team
657msh >timeslice_sample
658msh >thread 1 is running ,thread 1 count = 0
659thread 1 is running ,thread 1 count = 5
660thread 1 is running ,thread 1 count = 10
661thread 1 is running ,thread 1 count = 15
662663thread 1 is running ,thread 1 count = 125
664thread 1 is rthread 2 is running ,thread 2 count = 0
665thread 2 is running ,thread 2 count = 5
666thread 2 is running ,thread 2 count = 10
667thread 2 is running ,thread 2 count = 15
668thread 2 is running ,thread 2 count = 20
669thread 2 is running ,thread 2 count = 25
670thread 2 is running ,thread 2 count = 30
671thread 2 is running ,thread 2 count = 35
672thread 2 is running ,thread 2 count = 40
673thread 2 is running ,thread 2 count = 45
674thread 2 is running ,thread 2 count = 50
675thread 2 is running ,thread 2 count = 55
676thread 2 is running ,thread 2 count = 60
677thread 2 is running ,thread 2 cunning ,thread 2 count = 65
678thread 1 is running ,thread 1 count = 135
679680thread 2 is running ,thread 2 count = 205
681```
682
683As can be seen from the running count results, thread 2 runs half the time of thread 1.
684
685## Thread Scheduler Hook Sample
686
687When thread is scheduling switch, it executes the schedule. We can set a scheduler hook so that we can do other things when the thread is being switched. This sample is printing switch information between the threads in the scheduler hook function, as shown in the following code.
688
689```c
690#include <rtthread.h>
691
692#define THREAD_STACK_SIZE   1024
693#define THREAD_PRIORITY     20
694#define THREAD_TIMESLICE    10
695
696/* Counter for each thread */
697volatile rt_uint32_t count[2];
698
699/* Threads 1, 2 share an entry, but the entry parameters are different */
700static void thread_entry(void* parameter)
701{
702    rt_uint32_t value;
703
704    value = (rt_uint32_t)parameter;
705    while (1)
706    {
707        rt_kprintf("thread %d is running\n", value);
708        rt_thread_mdelay(1000); // Delay for a while
709    }
710}
711
712static rt_thread_t tid1 = RT_NULL;
713static rt_thread_t tid2 = RT_NULL;
714
715static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to)
716{
717    rt_kprintf("from: %s -->  to: %s \n", from->name , to->name);
718}
719
720int scheduler_hook(void)
721{
722    /* Set the scheduler hook */
723    rt_scheduler_sethook(hook_of_scheduler);
724
725    /* Create Thread 1 */
726    tid1 = rt_thread_create("thread1",
727                            thread_entry, (void*)1,
728                            THREAD_STACK_SIZE,
729                            THREAD_PRIORITY, THREAD_TIMESLICE);
730    if (tid1 != RT_NULL)
731        rt_thread_startup(tid1);
732
733    /* Create Thread 2 */
734    tid2 = rt_thread_create("thread2",
735                            thread_entry, (void*)2,
736                            THREAD_STACK_SIZE,
737                            THREAD_PRIORITY,THREAD_TIMESLICE - 5);
738    if (tid2 != RT_NULL)
739        rt_thread_startup(tid2);
740    return 0;
741}
742
743/* Export to msh command list */
744MSH_CMD_EXPORT(scheduler_hook, scheduler_hook sample);
745```
746
747The simulation results are as follows:
748
749```
750 \ | /
751- RT -     Thread Operating System
752 / | \     3.1.0 build Aug 27 2018
753 2006 - 2018 Copyright by rt-thread team
754msh > scheduler_hook
755msh >from: tshell -->  to: thread1
756thread 1 is running
757from: thread1 -->  to: thread2
758thread 2 is running
759from: thread2 -->  to: tidle
760from: tidle -->  to: thread1
761thread 1 is running
762from: thread1 -->  to: tidle
763from: tidle -->  to: thread2
764thread 2 is running
765from: thread2 -->  to: tidle
766767```
768
769It can be seen from the simulation results that when the threads are being switched, the set scheduler hook function is working normally and printing the information of the thread switching, including switching to the idle thread.
770