# Semaphore - [Basic Concepts](#section1577111168131) - [Working Principles](#section118423019134) - [Development Guidelines](#section01419503131) - [Available APIs](#section1232345431312) - [How to Develop](#section154261711141419) - [Development Example](#section658135571417) - [Example Description](#section125244411653) - [Sample Code](#section1742105514512) - [Verification](#section11297301617) ## Basic Concepts Semaphore is a mechanism for implementing inter-task communication. It implements synchronization between tasks or exclusive access to shared resources. In the data structure of a semaphore, there is a value indicating the number of shared resources available. The value can be: - **0**: The semaphore is unavailable. Tasks waiting for the semaphore may exist. - Positive number: The semaphore is available. The semaphore for synchronization is different from the semaphore for mutex: - Semaphore used for exclusive access: The initial semaphore counter value is not 0, indicating the number of shared resources available. The semaphore counter value must be acquired before a shared resource is used, and released after the resource is used. When all shared resources are used, the semaphore counter is reduced to 0 and the tasks that need to obtain the semaphores will be blocked. This ensures exclusive access to shared resources. In addition, when the number of shared resources is 1, a binary semaphore \(similar to the mutex mechanism\) is recommended. - Semaphore used for synchronization: The initial semaphore counter value is 0. Task 1 cannot acquire the semaphore and is blocked. Task 1 enters Ready or Running state only when the semaphore is released by task 2. In this way, task synchronization is implemented. ## Working Principles Semaphore control block ``` /** * Data structure of the semaphore control block */ typedef struct { UINT16 semStat; /* Semaphore status */ UINT16 semType; /* Semaphore type*/ UINT16 semCount; /* Semaphore count*/ UINT16 semId; /* Semaphore index*/ LOS_DL_LIST semList; /* Mount the task blocked by the semaphore.*/ } LosSemCB; ``` Working Principles Semaphore allows only a specified number of tasks to access a shared resource at a time. When the number of tasks accessing the resource reaches the limit, other tasks will be blocked until the semaphore is released. - Semaphore initialization The system allocates memory for the semaphores configured \(you can configure the number of semaphores using the **LOSCFG\_BASE\_IPC\_SEM\_LIMIT** macro\), initializes all semaphores to be unused semaphores, and adds them to a linked list for the system to use. - Semaphore creation The system obtains a semaphore from the linked list of unused semaphores and assigns an initial value to the semaphore. - Semaphore request If the counter value is greater than 0, the system allocates a semaphore, decreases the value by 1, and returns a success message. Otherwise, the system blocks the task and adds the task to the end of a task queue waiting for semaphores. The wait timeout period can be set. - Semaphore release When a semaphore is released, if there is no task waiting for it, the counter is increased by 1. Otherwise, the first task in the wait queue is woken up. - Semaphore deletion The system sets a semaphore in use to unused state and inserts it to the linked list of unused semaphores. The following figure illustrates the semaphore working mechanism. **Figure 1** Semaphore working mechanism ![](figure/semaphore-working-mechanism-22.png "semaphore-working-mechanism-22") ## Development Guidelines ### Available APIs **Table 1** Semaphore module APIs

Category

API

Description

Creating or deleting a semaphore

LOS_SemCreate

Creates a semaphore and returns the semaphore ID.

LOS_BinarySemCreate

Creates a binary semaphore. The maximum counter value is 1.

LOS_SemDelete

Deletes a semaphore.

Requesting or releasing a semaphore

LOS_SemPend

Requests a specified semaphore and sets the timeout period.

LOS_SemPost

Posts (releases) a semaphore.

### How to Develop 1. Call **LOS\_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS\_BinarySemCreate**. 2. Call **LOS\_SemPend** to request a semaphore. 3. Call **LOS\_SemPost** to release a semaphore. 4. Call **LOS\_SemDelete** to delete a semaphore. >![](../public_sys-resources/icon-note.gif) **NOTE:** >As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts. ### Development Example ### Example Description This example implements the following: 1. Create a semaphore in task **ExampleSem** and lock task scheduling. Create two tasks **ExampleSemTask1** and **ExampleSemTask2** \(with higher priority\). Enable the two tasks to request the same semaphore. Unlock task scheduling. Enable task **ExampleSem** to enter sleep mode for 400 ticks. Release the semaphore in task **ExampleSem**. 2. Enable** ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. \(When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.\) 3. Enable **ExampleSemTask1** to request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended. **ExampleSemTask1** is woken up after 10 ticks.\) Enable **ExampleSemTask1** to request the semaphore in permanent block mode after it is woken up 10 ticks later. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended.\) 4. After 20 ticks, **ExampleSemTask2** is woken up and releases the semaphore. **ExampleSemTask1** acquires the semaphore and is scheduled to run. When **ExampleSemTask1** is complete, it releases the semaphore. 5. Task **ExampleSem** is woken up after 400 ticks and deletes the semaphore. ### Sample Code The sample code is as follows: ``` #include "los_sem.h" #include "securec.h" /* Task ID*/ static UINT32 g_testTaskId01; static UINT32 g_testTaskId02; /* Task priority */ #define TASK_PRIO_TEST 5 /* Semaphore structure ID*/ static UINT32 g_semId; VOID ExampleSemTask1(VOID) { UINT32 ret; printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks.*/ ret = LOS_SemPend(g_semId, 10); /* The semaphore is acquired.*/ if (ret == LOS_OK) { LOS_SemPost(g_semId); return; } /* The semaphore is not acquired when the timeout period has expired.*/ if (ret == LOS_ERRNO_SEM_TIMEOUT) { printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); /* Request the semaphore in permanent block mode.*/ ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); printf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); if (ret == LOS_OK) { LOS_SemPost(g_semId); return; } } } VOID ExampleSemTask2(VOID) { UINT32 ret; printf("ExampleSemTask2 try get sem g_semId wait forever.\n"); /* Request the semaphore in permanent block mode.*/ ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); if (ret == LOS_OK) { printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); } /* Enable the task to enter sleep mode for 20 ticks.*/ LOS_TaskDelay(20); printf("ExampleSemTask2 post sem g_semId.\n"); /* Release the semaphore.*/ LOS_SemPost(g_semId); return; } UINT32 ExampleSem(VOID) { UINT32 ret; TSK_INIT_PARAM_S task1; TSK_INIT_PARAM_S task2; /* Create a semaphore.*/ LOS_SemCreate(0, &g_semId); /* Lock task scheduling.*/ LOS_TaskLock(); /* Create task 1.*/ (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; task1.pcName = "TestTask1"; task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; task1.usTaskPrio = TASK_PRIO_TEST; ret = LOS_TaskCreate(&g_testTaskId01, &task1); if (ret != LOS_OK) { printf("task1 create failed .\n"); return LOS_NOK; } /* Create task 2.*/ (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; task2.pcName = "TestTask2"; task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; task2.usTaskPrio = (TASK_PRIO_TEST - 1); ret = LOS_TaskCreate(&g_testTaskId02, &task2); if (ret != LOS_OK) { printf("task2 create failed.\n"); return LOS_NOK; } /* Unlock task scheduling.*/ LOS_TaskUnlock(); ret = LOS_SemPost(g_semId); /* Enable the task to enter sleep mode for 400 ticks.*/ LOS_TaskDelay(400); /* Delete the semaphore. */ LOS_SemDelete(g_semId); return LOS_OK; } ``` ### Verification The development is successful if the return result is as follows: ``` ExampleSemTask2 try get sem g_semId wait forever. ExampleSemTask2 get sem g_semId and then delay 20 ticks. ExampleSemTask1 try get sem g_semId, timeout 10 ticks. ExampleSemTask1 timeout and try get sem g_semId wait forever. ExampleSemTask2 post sem g_semId. ExampleSemTask1 wait_forever and get sem g_semId. ```