Introduction to RTOS Part 7 - Semaphore | Digi-Key Electronics

แชร์
ฝัง
  • เผยแพร่เมื่อ 21 ก.พ. 2021
  • A semaphore is a signaling mechanism used to synchronise two or more threads. Similar to a mutex, it can be used to protect shared resources. In this video, we show you how to use semaphores with FreeRTOS on an ESP32 to pass data between tasks.
    The starting code for the challenge can be found here: github.com/ShawnHymel/introdu...
    The solution to the challenge in the video can be found here: www.digikey.com/en/maker/proj...
    Code for this video series (including demonstrations, challenges, and solutions) can be found here: github.com/ShawnHymel/introdu...
    A semaphore is similar to a mutex in that it is a locking mechanism used to tell tasks to wait if some resource is not available for use. However, semaphores are more than a simple lock: they can count to more than 1 and can therefore allow multiple threads to enter a critical section of code.
    In practice, however, we often do not want to let multiple threads manipulate shared data, and we would still need to protect that data (or shared resource) with something like a mutex. So, we use semaphores as a signaling mechanism to tell other threads when it is safe to access a resource or read new data.
    A buffer or linked list can be written to by a number of “producer” threads. Each time one of these producer threads adds data to this resource, it increments a semaphore, which is just a counting variable that can be accessed atomically. When a “consumer” thread wishes to read data from the resource, it decrements the semaphore count. If the semaphore is 0, that means no new data is available, so consumer threads must wait (e.g. enter the blocked state).
    Semaphores work similarly to mutex, but are generally used in different circumstances. We provide examples of these use cases in the video as well as issue a challenge to use semaphores on your own.
    Product Links:
    www.digikey.com/en/products/d...
    Related Videos:
    Introduction to RTOS Part 1 - What is a Real-Time Operating System (RTOS)? - • Introduction to RTOS P... ​
    Introduction to RTOS Part 2 - Getting Started with FreeRTOS - • Introduction to RTOS P... ​
    Introduction to RTOS Part 3 - Task Scheduling - • Introduction to RTOS P... ​
    Introduction to RTOS Part 4 - Memory Management - • Introduction to RTOS P... ​
    Introduction to RTOS Part 5 - Queue - • Introduction to RTOS P... ​
    Introduction to RTOS Part 6 - Mutex - • Introduction to RTOS P... ​
    Introduction to RTOS Part 7 - • Introduction to RTOS P... ​
    Introduction to RTOS Part 8 - • Introduction to RTOS P...
    Introduction to RTOS Part 9 - • Introduction to RTOS P...
    Introduction to RTOS Part 10 - • Introduction to RTOS P...
    Introduction to RTOS Part 11 - • Introduction to RTOS P...
    Introduction to RTOS Part 12 - • Introduction to RTOS P...
    Related Project Links:
    www.digikey.com/en/maker/proj...
    Related Articles:
    www.digikey.com/en/maker/vide...
    Learn more:
    Maker.io - www.digikey.com/en/maker
    Digi-Key’s Blog - TheCircuit www.digikey.com/en/blog
    Connect with Digi-Key on Facebook / digikey.electronics
    And follow us on Twitter / digikey
  • วิทยาศาสตร์และเทคโนโลยี

ความคิดเห็น • 63

  • @haakonness
    @haakonness 2 ปีที่แล้ว +2

    Wow! You helped me finally understand the greatness of semaphores. I've always only heard the "multiple threads can enter" part, and not seen the value of it. Thanks!

  • @danielaariashoyos4160
    @danielaariashoyos4160 2 ปีที่แล้ว +3

    Excellent video! I have followed all the tutorials and the way you explain and exemplifies the different scenarios is awesome. Thank you

  • @ikocheratcr
    @ikocheratcr 3 ปีที่แล้ว +5

    Nice series, clean intro to FreeRTOS.

  • @michalkovacik9126
    @michalkovacik9126 2 ปีที่แล้ว +3

    Thank you very much. While studying the FREERTOS manual, I got lost in the details and didn't see the main things. These videos are great in that they explain the main things with examples. One immediately understands how to use it and why it is good.

  • @ytubeleo
    @ytubeleo 3 ปีที่แล้ว +4

    I hope there's a Part 8 in the works! Everyone hit like so that Digi-Key knows the series is popular!!

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +2

      It is! I have 12 parts planned for this series :)

    • @ytubeleo
      @ytubeleo 3 ปีที่แล้ว

      @@ShawnHymel Sweet. Your videos are very good! Thanks

    • @ytubeleo
      @ytubeleo 3 ปีที่แล้ว

      @@ShawnHymel Will you be doing a video on DMA with ESP32? For example, ADC to DMA, etc. That would be really useful and there doesn't seem to be a good video about it on TH-cam. Thanks!

  • @neoXXquick
    @neoXXquick 3 ปีที่แล้ว +5

    Amazing series i want more...

  • @morezco
    @morezco 2 ปีที่แล้ว +1

    You are excellent with your lectures!

  • @m5r217
    @m5r217 3 ปีที่แล้ว +1

    Great explanation. Thanx!

  • @MarlosZappa
    @MarlosZappa 3 ปีที่แล้ว +2

    Great stuff, thanks!

  • @linajafari3299
    @linajafari3299 3 ปีที่แล้ว +2

    Great videos, thanks !

  • @aeljandro2
    @aeljandro2 2 ปีที่แล้ว

    I love this!! Thanks, digikey!

  • @MuhammadDaudkhanTV100
    @MuhammadDaudkhanTV100 3 ปีที่แล้ว +1

    Really good ideas and good work

  • @adityahirwani1672
    @adityahirwani1672 5 หลายเดือนก่อน

    You are excellent with your lectures!🤩🤩

  • @elliottgoldstein2035
    @elliottgoldstein2035 ปีที่แล้ว

    Hey Shawn:
    Am I correct in understanding we'd still need another way of managing the possible conflict over which producer/consumer gets to access the buffer first? if a producer gives the semaphore
    and places a value in the buffer, how can we tell which consumer would give access to it first? Is it non-deterministic? Would we have to use a mutex to prevent a race condition of both attempting to access the buffer at the same time? Do they have to be made different priorities?

  • @chianlee1381
    @chianlee1381 ปีที่แล้ว

    Hi, very good explanations! I am wondering why is the number print out unorderly. If we create the tasks in the loop one after one, the producer should finish its task with no taskdelay. I think that means there is no time for other producer tasks to write into the buffer? Can anybody tell me what's going on here? Thanks a lot!

  • @gaelc13
    @gaelc13 3 ปีที่แล้ว +7

    The RHS of the slide at 6:24 should probably read semaphoreTake(semaphore) instead of semaphoreTake(mutex)

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +3

      Good catch! You are correct...it should match the semaphoreGive(semaphore) line above it.

  • @xidameng
    @xidameng 3 ปีที่แล้ว +1

    Hi, thanks for sharing your knowledge! I have watched the entire series and look forward to more! Just a simple question, for the counting sem example, in the for loop that creates 5 tasks, does program execute each task immediately after creating it and only after it loops for 5 times then the program goes into the "xSemaphoreTake" for loop?

    • @xidameng
      @xidameng 3 ปีที่แล้ว

      I am asking this bcos looking at the code itself, it just doesn't feel necessary to xSemaphoreTake 5 times at the end since nobody else is gonna use the sem anyway

    • @xidameng
      @xidameng 3 ปีที่แล้ว

      If I am right, then can we add the "xSemaphoreTake()" directly to the end of the tasking-creating for loop? Wouldn't it be safer this way? and also save number of sem needed to just 2 since it give and take right away

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +5

      @@xidameng Yes, each task begins executing immediately after creation. The "setup and loop" task would continue to execute concurrently with each of the 5 tasks (in this case, in a round-robin fashion, as they're all priority 1). Taking all 5 semaphores in the for loop forces the "setup and loop" task to wait until all 5 other tasks reached the "xSemaphoreGive()" line. You could also immediately take a semaphore after creating a task in the task creation loop, but that has a slightly different effect: it would force the "setup and loop" task to wait until each task reached the "xSemaphoreGive()" line before creating the next task. Hope that helps!

  • @BryanChance
    @BryanChance ปีที่แล้ว

    Would semaphores be used in async or nonblocking i/o operations?

  • @yasir45982
    @yasir45982 ปีที่แล้ว

    Thanks for information.
    I think Mutex & Semaphere issues are hard

  • @vex123
    @vex123 10 หลายเดือนก่อน

    @5:30 I think there is a typo on the Semaphore example. Should be semaphoreTake(semphore), not semaphoreTake(mutex) I think.

  • @KaiseruSoze
    @KaiseruSoze 3 ปีที่แล้ว +3

    My favorite instruction pair: cli, sti for very short pieces of critical code. Cli disables all interrupts except non-maskable. Sti enables. Great for single core CPU, but not so much for multi-core. Also it's machine dependent. (assembly language)

    • @paulwojcik1856
      @paulwojcik1856 3 ปีที่แล้ว +1

      You disable interrupts (including timers, hardware interrupts, watchdogs, etc) to control access to shared resources. Probably OK in simple programs (as I used to do myself back in the 80's when running 4/8 bit micros, and would do so now for very simple embedded apps) but wouldn't use this approach for anything more complex, and certainly not in the context of an app that is considering an RTOS.

    • @JonitoFischer
      @JonitoFischer 2 ปีที่แล้ว

      If you are doing digital signal processing or digital control algorithms in a DSP (yes, some ARM Cortex-M processors can be considered as DSPs) you're loosing synchronization in the sample time if you disable all interrupts. Moreover, these interrupts should run as kernel unaware interrupts in FreeRTOS, so the scheduler doesn't prevent them to run when they are supposed to run.

  • @gustavovelascoh
    @gustavovelascoh 3 ปีที่แล้ว +1

    Sticking to the coffee shop scenario, could semaphore be seen as the mechanism of sharing orders between waiters and cooks? On the other hand, Could it be used for a logging process where different tasks send messages to a buffer and then they are broadcasted through, let say, UART?

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +4

      If I'm following your analogy correctly, I think you would want a queue for that type of message passing. However, let's say that instead of separate slips of paper, customer orders are all written on a whiteboard that's shared between waiters and cooks. Each time a waiter writes an order on the whiteboard, they increment a giant 7-segment display that all the cooks and waiters can see. This 7-segment display would be the semaphore. Each time a cook starts to process one of the orders, they erase it from the whiteboard and push a button to decrement the 7-segment display. When the display is '0', all the cooks know that there are no more orders. Let's say it's a single-digit 7-segment display, which means it can only display 0-9. When it reaches the max value (9), the waiters know not to add anything more to the whiteboard until the counter is decremented. Does that help?

  • @gopalagrawal2270
    @gopalagrawal2270 2 ปีที่แล้ว

    what is problem with binary semaphore to use for protection of shared resource?

  • @alchimie2803
    @alchimie2803 2 ปีที่แล้ว

    I can't Understand why some people do dislike to these videos.

  • @skelstar
    @skelstar 3 ปีที่แล้ว +1

    So if I had a queue, and I want all of my tasks to "peek" the queue to get the value, I would use a counting semaphore to indicate the all of the tasks have read the queue?
    Trying to think of how I could use a counting semaphore.

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว

      If you want to peek at a value in a FreeRTOS queue, you could use xQueuePeek(). Counting semaphores could be useful for things like controlling reads/writes to/from an unbounded buffer or linked list.

    • @skelstar
      @skelstar 3 ปีที่แล้ว +1

      @@ShawnHymel I was thinking that the problem with peeking is that eventually something was going to have to read the item/value off the queue, and a counting semaphore would used to tell the queue "manager" that everyone has peeked the value. Could just use a normal counter anyway I guess :)
      Great video. A++!

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +1

      @@skelstar You could use a counting semaphore there, too. If you used a global variable as a counter, you'd want to make sure reading/writing was atomic to avoid a race condition.

  • @piconano
    @piconano 3 ปีที่แล้ว +1

    I think most MCUs now support read-modify-write instructions that works in one cycle on a RISC.
    Am I wrong? It's been a long time since I worked with semaphores.

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +1

      I think you are correct. Maybe some older 8- or 16-bit MCUs that weren't made for multithreading don't support those instructions, but I haven't stared at an assembly instruction set since PIC and AVR :)

  • @GBRiLFLRNTiN
    @GBRiLFLRNTiN 18 วันที่ผ่านมา

    didnt do any of these challenges... you really could add a final video with them (Y)

  • @ytubeleo
    @ytubeleo 3 ปีที่แล้ว +1

    Can you make the code window a bit bigger, please? You could easily cut off the coloured bar and log window at the bottom, and even everything above "sketch_jan27a" is irrelevant too. You could make the window wider and use a larger font for people using mobile devices or poor internet connections 😊

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว +1

      Thanks for the tip--I'll see if I can make it easier to read for future episodes (everything up to part 12 has already been recorded, though).

  • @fc3fc354
    @fc3fc354 7 หลายเดือนก่อน +1

    Can somebody explain what's the meaning of
    Int num =*(int *) parameters
    Min 7:56
    Exactly what does *(int *) parameters mean

    • @JacksonBockus
      @JacksonBockus หลายเดือนก่อน

      (int *)parameters casts parameters to the type int *. This tells the compiler to treat what is pointed to as an int. Adding the extra star before it tells it to dereference that pointer. So int num = *(int *)parameters tells the compiler "Treating parameters as a pointer to an integer, take the integer pointed to and copy it to num"

  • @1deepakbharti
    @1deepakbharti 2 ปีที่แล้ว

    while compiling in Arduino following error occur
    Can you help me with this?
    Semaphore:68:36: error: 'xSemophoreCreateBinary' was not declared in this scope
    bin_sem = xSemophoreCreateBinary();
    ^
    exit status 1
    'xSemophoreCreateBinary' was not declared in this scope

    • @sigridgosliga5797
      @sigridgosliga5797 2 ปีที่แล้ว +1

      How about xSemaphoreCreateBinary? I think you made a typo --> Sema instead of Semo.

    • @1deepakbharti
      @1deepakbharti 2 ปีที่แล้ว

      @@sigridgosliga5797 Thanks

  • @ksawery6568
    @ksawery6568 3 ปีที่แล้ว

    I don't understand why two semaphores are needed in the solution to the challenge, couldn't a single semaphore be used to count the number of objects in the buffer?

    • @ksawery6568
      @ksawery6568 3 ปีที่แล้ว +2

      Never mind, I now understand why that's required. If only a single semaphore was used, the consumer task could take that semaphore, but right before it would read the buffer, the scheduler could switch back to the producer task. The producer task would then successfully give the semaphore (as it had just been taken) and continue to write to the buffer before the consumer was ever able to read it. This would result in overrun errors. The same thing applies the other way around - i.e. the consumer task reading before anything was written.

  • @caiomolinari4790
    @caiomolinari4790 3 ปีที่แล้ว +1

    Can you create semaphores manually? For example, if I create an int flag that counts up to five, would it work like a semaphore?

    • @MarlosZappa
      @MarlosZappa 3 ปีที่แล้ว +3

      I believe the reason you would want to avoid the manual work is because the in-/decrementing operations would not be atomic, as the built-in FreeRTOS semaphore functions that he demonstrates are. That would mean some global int used as a semaphore would be susceptible to race conditions, and you would get non-deterministic behavior i.e. you couldn't really trust that value to be precise. This could then lead you to buffer overflows and the kinds of problems you'd want to avoid by having atomic operations.

    • @caiomolinari4790
      @caiomolinari4790 3 ปีที่แล้ว +1

      @@MarlosZappa that makes total sense, thanks

  • @user-nt5qi2rm8y
    @user-nt5qi2rm8y 3 ปีที่แล้ว +1

    Hi Shawn, I tried to fix the messed up "Serial.print("Received: "); ......." with a mutex encapsulating the four lines of "Serial.print()" functions, but it did not solve the issue. I couldn't think of why. any suggestion would be appreciated!

    • @ShawnHymel
      @ShawnHymel 3 ปีที่แล้ว

      Hmmm...interesting. I admit that I did not try it before saying that in the video, so I might have to give it a shot (I don't have my ESP32 on hand right now). I wonder if it has to do with how Serial messages are queued up in an external buffer and then send out using hardware interrupts. Maybe try adding a Serial.flush() line at the end of the Serial commands (before returning the mutex) to force the Serial buffer to finish writing out?

  • @kocokan
    @kocokan 3 ปีที่แล้ว +3

    after following your series
    I can confidently concluded:
    I need a bowtie

  • @abhishekgarg9673
    @abhishekgarg9673 3 ปีที่แล้ว

    Please make the video how we can get data from API with user type

    • @abhishekgarg9673
      @abhishekgarg9673 3 ปีที่แล้ว

      ESP32 when u type a key And print the Value with freeRTOS

    • @abhishekgarg9673
      @abhishekgarg9673 3 ปีที่แล้ว

      Please help to make the video on it

  • @DeVibe.
    @DeVibe. 25 วันที่ผ่านมา

    FreeRTOS, not RTOS.