My hands-on experience sharing Inter-thread synchronization (Semaphore)

Created at 2020-12-11 10:58:49

Forwarded from RT-Thread Community Developer


semaphore is essentially an IPC kernel object for interthread synchronization, and how many resources can be allocated in a semaphore object is determined by its value (the value because of its data type rt_uint16_t, with a maximum value of 65535).

Structure of the semaphore:

struct rt_semaphore
    struct rt_ipc_object parent;

    rt_uint16_t          value;

Therefore, at the time of initialization, its initial value needs to be assigned. For example:

Initialize two threads with different priorities, and when the'value' is initialized to 0, the thread can suspend the high-priority thread by permanently acquiring 'rt_sem_take (sem, RT_WAITTING_FOREVER) and then let the low-priority thread run, the low-priority thread can run by releasing the semaphore of 'rt_sem_release(sem)' to let the high-priority thread get the semaphore to run, suspending the low-priority thread.

Another example:

Initialize two threads with the same priority, and when the 'value' is initialized to a certain value, by each of the two threads obtaining the semaphore 'rt_sem_take(sem, RT_WAITTING_FOREVER)', and then after running to a certain extent the semaphore is taken, one thread will be suspended and the other thread will run alone.

Notes: Threads generally cannot be forcibly deleted directly, generally only by letting them end on their own, and then by letting idle threads recycle threads, so you need to use semaphore when the program runs after the end of a thread can not permanently suspend a thread, that is, no resources are released, resulting in memory leakage.
Note: When a thread acquires a semaphore, it only has effect on threads that want to get semaphore, has no effect on other threads, and does not generate a signal priority flip, i.e. the thread's current priority does not change because it is interrupted by a high-priority thread.

Where the acquisition and release of semaphore can run not only in a thread environment, but also in an interrupt environment.

The difference between dynamically creating rt_sem_create and static initialization rt_sem_init: Dynamic creation is dynamically applying memory sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name); Static initialization can directly initialize the rt_ipc_object_init(&(sem->parent)) without applying the memory;
The corresponding deletion actions rt_sem_delete and the detach operation rt_sem_detach execute rt_object_detach(&(sem->parent.parent)) and rt_object_delete(&(sem->parent.parent)) respectively after waking up all suspended threads.

The only difference between the detach kernel rt_object_detach(&(sem->parent.parent)) and the delete kernel rt_object_delete(&(sem->parent.parent)) is that the value of the amount of the kernel resource RT_KERNEL_FREE(object) was finally released during the deletion and the value of the semaphore was not deleted after semaphore deleted. Just set it from its kernel type to 0 and remove it from the kernel queue, where the true value and corresponding pointer have not changed.

The semaphore flag has two settings, the first-in and first-out principle RT_IPC_FLAG_FIFOand the priority principle RT_IPC_FLAG_PRIO, and in order to verify this feature, I've written the code to test:

#include <rtthread.h>

static rt_thread_t thread1, thread2;
static rt_sem_t sem;

static void thread1_entry(void *paramter)
        rt_sem_take(sem, RT_WAITING_FOREVER);
        rt_kprintf("run thread1.<br>");

static void thread2_entry(void *paramter)
        rt_sem_take(sem, RT_WAITING_FOREVER);
        rt_kprintf("run thread2.<br>");

int test_sample(void)
        sem = rt_sem_create("semapore", 0, RT_IPC_FLAG_FIFO);
        if (sem == RT_NULL)
                rt_kprintf("Create semapore failed.<br>");
                return -1;
        thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, 1024, 16, 10);
        thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, 1024, 15, 10);
        if (thread1 != RT_NULL)

        return 0;

MSH_CMD_EXPORT(test_sample, test sample);

When set the flag to RT_IPC_FLAG_FIFO, the output is

msh >test_sample
run thread1.
run thread2.

When set the flag to RT_IPC_FLAG_FIFO, the output is:

msh >test_sample
run thread1.
run thread2.

You are welcome to share your ideas with this.


0 Answer
There is no answer, come and add the answer

Write Your Answer

Log in to publish your answer.,Click here to log in.