BLOG記事用論壇

 找回密碼
 註冊
搜索
熱搜:
查看: 1105|回復: 0

Critical Sections "semaphores" , "mutex"

[複製鏈接]
發表於 2023-6-6 04:28:04 | 顯示全部樓層 |閱讀模式

Semaphores:

Semaphores can be binary or counting. A binary semaphore is similar to a mutex but without the ownership rule.
Semaphores are typically used for two types of synchronization problems: mutual exclusion (protecting access to a critical section of code, similar to a mutex) and deadlock avoidance (for example, to coordinate multiple tasks accessing a finite pool of resources).
A semaphore can be "given" (signalled) by the task that did not take it, which is not possible with mutexes.
Mutexes:

Mutex (short for Mutual Exclusion) is specifically designed to protect a critical section of code, ensuring that only one task can execute the code at a time. A critical section of code typically involves access to shared resources like global variables, a communication interface, etc.
A mutex incorporates the concept of "ownership", i.e., only the task that has taken (locked) the mutex can give it back (unlock it). This rule does not apply to semaphores.
Mutexes in uC/OS-II include a priority inheritance mechanism. If a higher-priority task is blocked by a lower-priority task (which is currently owning the mutex), the lower-priority task temporarily inherits the higher priority to prevent priority inversion problem. Semaphores in uC/OS-II do not include a priority inheritance mechanism.
  1. OS_EVENT *dataSem;

  2. // Producer Task
  3. void producer(void) {
  4.     while(1) {
  5.         // Generate data here...

  6.         // Signal that data is ready
  7.         OSSemPost(dataSem);
  8.     }
  9. }

  10. // Consumer Task
  11. void consumer(void) {
  12.     while(1) {
  13.         // Wait for data to be ready
  14.         OSSemPend(dataSem, 0, &err);

  15.         // Process data here...
  16.     }
  17. }
複製代碼
  1. OS_EVENT *resourceMutex;

  2. // Task 1
  3. void task1(void) {
  4.     while(1) {
  5.         // Wait to lock the mutex before accessing the shared resource
  6.         OSMutexPend(resourceMutex, 0, &err);

  7.         // Access shared resource here...

  8.         // Release the mutex when finished with the shared resource
  9.         OSMutexPost(resourceMutex);
  10.     }
  11. }

  12. // Task 2
  13. void task2(void) {
  14.     while(1) {
  15.         // Wait to lock the mutex before accessing the shared resource
  16.         OSMutexPend(resourceMutex, 0, &err);

  17.         // Access shared resource here...

  18.         // Release the mutex when finished with the shared resource
  19.         OSMutexPost(resourceMutex);
  20.     }
  21. }
複製代碼


OS_CRITICAL_METHOD
uC/OS-II provides three methods to manage interrupts during critical sections which are configured using the OS_CRITICAL_METHOD macro. This macro can take one of three values: 1, 2, or 3. Each of these methods provides a different way of managing the processor’s interrupt flag.

OS_CRITICAL_METHOD=1:
This method is the simplest and can be used on any processor. It uses a local variable to keep track of the interrupt status. It saves the interrupt status into a local variable and then disables interrupts. When leaving the critical section, it restores the interrupt status from the local variable. This method doesn't support nested critical sections.

OS_CRITICAL_METHOD=2:
This method also can be used on any processor. Unlike method 1, it supports nested critical sections. It uses a global counter OSIntNesting to keep track of the interrupt status. When entering a critical section, it increments the counter and disables interrupts. When leaving the critical section, it decrements the counter. If the counter is 0, it enables interrupts; otherwise, it keeps interrupts disabled.

Method 3 is similar to method 2 but also saves the interrupt status into OSIntNesting.

In summary, the difference between method 1 and method 2 is that method 1 doesn't support nested critical sections while method 2 does. This means that if you're using method 1, you can't have a critical section inside another critical section. If you do, the inner critical section could re-enable interrupts prematurely. Method 2 doesn't have this limitation because it keeps interrupts disabled until the outermost critical section has finished.

uC/OS-II may choose to use OS_CRITICAL_METHOD=2 to handle critical sections for a few reasons:

Nested Critical Sections: This method allows for nested critical sections. This is important in more complex systems where a function called within a critical section may also contain critical sections. With method 2, the system properly handles this nesting, only re-enabling interrupts when it has exited all nested critical sections.

Flexibility and Consistency: Using a global counter like OSIntNesting to keep track of the depth of nested critical sections provides a consistent way of handling this across the system. This can make the system's behaviour more predictable and easier to understand and debug.

Safety: Method 2 makes the system more robust in the face of programming errors. For example, if a programmer mistakenly includes a return statement in the middle of a critical section, the system will not incorrectly re-enable interrupts, which could happen with method 1. Instead, interrupts will remain disabled until the outermost critical section has finished.

However, it's worth mentioning that this method may not be suitable for all systems. For example, in systems with very strict real-time requirements, the extra time taken to increment and decrement the counter might not be acceptable. The choice of method will depend on the specific requirements and constraints of the system.

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

手機版|Archiver|綜合討論區

GMT+8, 2026-6-24 18:47 , Processed in 0.063292 second(s), 8 queries , File On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表