# Shared resource between task and ISR

**URL:** <https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685>\
**Category:** Kernel\
**Created:** [October 27, 2025, 1:29pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685 "2025-10-27T13:29:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![vigneshv1](https://avatars.discourse-cdn.com/v4/letter/v/9dc877/32.png) [@vigneshv1](https://forums.freertos.org/u/vigneshv1)\
**Post date:** [October 27, 2025, 1:29pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/1 "2025-10-27T13:29:22Z")

</div>

Hi FreeRtos community,

So there is a global variable that needs to be modified by a task and ISR how can I handle this efficiently?

I know there are two ways for this.

1. I can use enter and exit critical while accessing from task.

2. I can use mutex.

apart from these two any other ways are there?

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [October 27, 2025, 1:38pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/2 "2025-10-27T13:38:53Z")

</div>

The critical section is an overkill because it freezes all OS activities and all threads of computation while in effect. If you have a way to disable only the isr that competes with your task, that can help enhance throughput and prevent system freezes that result from improper use of the critical section.

And no, you can not use muteces in isrs. Just query the forum, it has been discussed a bazillion times.

---

<div class="post-metadata">

**Author:** ![vigneshv1](https://avatars.discourse-cdn.com/v4/letter/v/9dc877/32.png) [@vigneshv1](https://forums.freertos.org/u/vigneshv1)\
**Post date:** [October 27, 2025, 1:56pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/3 "2025-10-27T13:56:09Z")

</div>

Hi @RAc ,

Can you give me any conversation link related to why we should not use mutex in ISR?

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [October 27, 2025, 1:58pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/4 "2025-10-27T13:58:49Z")

</div>

use the forum search function and type “mutex isr” (no quotes) in the search field. It’ll jump right into your face.

---

<div class="post-metadata">

**Author:** ![richard-damon](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/richard-damon/32/38_2.png) [@richard-damon](https://forums.freertos.org/u/richard-damon)\
**Post date:** [October 27, 2025, 2:54pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/5 "2025-10-27T14:54:37Z")

</div>

> [@vigneshv1](#):
>
> Can you give me any conversation link related to why we should not use mutex in ISR?

The simplest is there is no _FromISR access functions for a Mutex, and even if you cheat and use the_ FromISR version of semaphore operations (which aren’t promised to work on the semaphore) you run into the issue that the ISR can’t wait for the Mutex to be ready, as it has blocked the task that held it (unless you are using SMP)

The _ONLY_ ways a task can protect access of something from an ISR is to use a critical section, which needs to be kept very short as it globally disables all interrupts, disable the specific interrupt that you are sharing with (if you know it), or use a flag variable that the ISR checks.

In the last case, the ISR needs to be able to work without accessing that thing, which often isn’t the case.

The other work around is the ISR triggers a high priority task to do what is needed to that object, using a ISR safe communications link.

---

<div class="post-metadata">

**Author:** ![kstribrn](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kstribrn/32/2085_2.png) [@kstribrn](https://forums.freertos.org/u/kstribrn)\
**Post date:** [October 27, 2025, 5:42pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/6 "2025-10-27T17:42:14Z")

</div>

If both the task and the ISR need to modify the variable then a critical section is your best bet. If you can design your application so that the ISR only writes and the task only consumes then you would be able to use fromISR APIs (placing signals into a queue for example).

---

<div class="post-metadata">

**Author:** ![vigneshv1](https://avatars.discourse-cdn.com/v4/letter/v/9dc877/32.png) [@vigneshv1](https://forums.freertos.org/u/vigneshv1)\
**Post date:** [October 28, 2025, 5:44am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/7 "2025-10-28T05:44:09Z")

</div>

So I have gone through some of the conversations, Now I understood why we should not use mutex from ISR.

But In which situation may I use this xSemaphoreGiveFromISR API?

---

<div class="post-metadata">

**Author:** ![richard-damon](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/richard-damon/32/38_2.png) [@richard-damon](https://forums.freertos.org/u/richard-damon)\
**Post date:** [October 28, 2025, 11:17am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/8 "2025-10-28T11:17:12Z")

</div>

My typical use of xSemaphoreGiveFromISR is for a I/O completion signal.

Task calls an device driver API that first takes a mutex for that device so it has control over it.

That driver then sets up and initiates the I/O operation, and then waits on the semaphore, and the processor goes off to run other tasks.

The interrupt system then completes the I/O operation, and when complete, signals the semaphore.

The driver, when it is gotten back to by again being the highest priority gathers the completion information set by the ISR, and then gives the device mutex to let another task use the device if it wants.

---

<div class="post-metadata">

**Author:** ![dc42](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/dc42/32/487_2.png) [@dc42](https://forums.freertos.org/u/dc42)\
**Post date:** [October 31, 2025, 8:52pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/9 "2025-10-31T20:52:07Z")

</div>

Depending on the type of the global variable, there may be other options. For example, if you are using C++ then there is the std::atomic template, which gives you the means to declare variables that you can atomically read, from add to, subtract from, and compare/exchange with. These typically work only on 32 or 64 bit variables, although 128-bit compare/exchange is available on some processors.

Other programming languages may provide language constructs to access the underlying machine instructions that std::atomic makes use of.

In some cases, you may not need atomic access if you design the data structure carefully. A common example is a ring buffer that the ISR writes to and a task reads from, or vice versa. You can avoid any need to use synchronisation primitives, provided that the get and put indices are small enough to be read from and written to memory in a single machine operation.

---

<div class="post-metadata">

**Author:** ![rvt](https://avatars.discourse-cdn.com/v4/letter/r/43a26b/32.png) [@rvt](https://forums.freertos.org/u/rvt)\
**Post date:** [November 2, 2025, 5:25pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/10 "2025-11-02T17:25:14Z")

</div>

You don’t have a lot for us to under what you really need…  
You talk about a shared resources, then mention it’s a variable.  
In general, variables are not resources…

That said, if it’s it’s a spamm variable, check if your hardware is already atomic. For example the Raspberry PI PICO write 32bits atomically… there is no need to ‘protect’ them.

Also remember, not all platforms support std::atomic, they simply wrap them, but they are not atomic. so Be careful when you use anything from c++.

Other options are SCSP queues (Single Producer, Single Consumer). They are lock feel, your ISR can push, and your other task can pop them, he advantage is, when the queue is large enough you won’t mis any changes from the ISR.  
Alternatively you can use the message services from FreeRTOS.

What I often use when it’s just a copy of some variable or small struct is to use a spinlock. As I work on the PICO a lot, and the PICO has hardware spinlocks they are very fast and don’t have the overhead of any messages or SCSP queues…

---

<div class="post-metadata">

**Author:** ![vigneshv1](https://avatars.discourse-cdn.com/v4/letter/v/9dc877/32.png) [@vigneshv1](https://forums.freertos.org/u/vigneshv1)\
**Post date:** [November 3, 2025, 5:10am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/11 "2025-11-03T05:10:58Z")

</div>

The shared resource that I have mentioned is sending data over uart. What if the situation comes like the task and ISR both needs to use uart\_send function?

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [November 3, 2025, 7:59am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/12 "2025-11-03T07:59:26Z")

</div>

That depends on how uart\_send() is implemented, I know very few iplementations that are safe to use in an isr in the first place. If you have such an implementation AND the control flow is sound, you need to be aware of the fact that isrs can never block, so if an isr detects that there is an ongoing task based transmission (using either of the strategies outlined above), the isr must return and employ some kind of way to trigger a deferred start of next transmit. There are ways to do that, but they need careful coding and bear a number of trap doors-

---

<div class="post-metadata">

**Author:** ![vigneshv1](https://avatars.discourse-cdn.com/v4/letter/v/9dc877/32.png) [@vigneshv1](https://forums.freertos.org/u/vigneshv1)\
**Post date:** [November 3, 2025, 8:56am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/13 "2025-11-03T08:56:30Z")

</div>

Hi @RAc ,

> [@RAc](#):
>
> There are ways to do that, but they need careful coding and bear a number of trap doors-

could you suggest me what are those I will give it a try once?

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [November 3, 2025, 9:11am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/14 "2025-11-03T09:11:11Z")

</div>

no. Without seeing the code for the serial driver you are using, everything is guess work. You will need to very deeply dig into the control flow, understand how it works and then modify it piece by piece, ending up likely with a driver rewritten from scratch.

One thing I have done in the past in a similar case is have every thread of execution (isr or task) that wants to transmit tuck its data at the end of the uart transmit buffer so that the xmit complete interrupt can work off everything in the buffer (ie an ongoing transmission AND new characters coming in in the mean time) until the buffer is empty, but a) there are several possible race conditions and interleaved scenarios to consider to get that to work reliably and b) that works only when each character transmission interrupts the mcu individually (bulk dma transmission will not work with that scheme).

By the time you are done with that, you will know more about serial device drivers than is good for you. Highly interesting and fun stuff, but not the kind of thing that managers are willing to pay for.

---

<div class="post-metadata">

**Author:** ![rvt](https://avatars.discourse-cdn.com/v4/letter/r/43a26b/32.png) [@rvt](https://forums.freertos.org/u/rvt)\
**Post date:** [November 3, 2025, 8:17pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/15 "2025-11-03T20:17:42Z")

</div>

I missed the UART usecase.

It sounds like you want to send from different tasks, and receive over the UART handle handle this.

It sounds like you want to send messages if they are single chars.  
if you want to send/receive multiple chars like strings you could use a FreeRTOS queue.

---

<div class="post-metadata">

**Author:** ![robert.berger](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/robert.berger/32/4739_2.png) [@robert.berger](https://forums.freertos.org/u/robert.berger)\
**Post date:** [November 4, 2025, 10:31am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/16 "2025-11-04T10:31:05Z")

</div>

The atomic data type works as well in C from C11[1], and I would check it out. The underlying mechanisms are typically memory barriers. If your chip supports “memory barriers”, you can also construct some primitives on your own if that’s necessary.

[1] [Atomic types - cppreference.com](https://en.cppreference.com/w/c/language/atomic.html)

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [November 4, 2025, 11:23am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/17 "2025-11-04T11:23:19Z")

</div>

I am surprised that atomic operations should be based on barriers. On ARM Cortex MCUs, atomic operations are based on the ldrex and strex primitives which to my best knowledge are not related to barriers. Could you elaborate? Thanks!

---

<div class="post-metadata">

**Author:** ![robert.berger](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/robert.berger/32/4739_2.png) [@robert.berger](https://forums.freertos.org/u/robert.berger)\
**Post date:** [November 4, 2025, 11:52am UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/18 "2025-11-04T11:52:36Z")

</div>

ldrex and strex only guarantee exclusive access to an address, they don’t guarantee the correct order of execution, they also do not prevent reordering in compile/runtime. In this example[1] you will not see any problem, but only the generated code with[2] and without[3] atomic data types.

[1] [/\* FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd. Thi - Pastebin.com](https://pastebin.com/ihrZx7ib)

[2] [https://pastebin.com/4svu31C9](https://pastebin.com/4svu31C9) note the dmb instructions

[3] [atomic-3 - Pastebin.com](https://pastebin.com/9V0GbKzc) no barriers

To be more precise, for atomic data types it seems to be a combination of ldrex/strex/dmb.

---

<div class="post-metadata">

**Author:** ![RAc](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rac/32/1389_2.png) [@RAc](https://forums.freertos.org/u/RAc)\
**Post date:** [November 4, 2025, 12:16pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/19 "2025-11-04T12:16:26Z")

</div>

Thanks for the links, Robert, this is highly interesting and enlightening reading. However, for the discussion at hand, we may be straying offsite. Please correct me if I am wrong (I may well be), but we may be talking about different ideas of “atomicity.” When it comes to mutual exclusion (both between tasks and tasks/isrs), there are scenarios in which exclusive access (frequently also named “atomic access,” although that may not be 100% precise according to your explanation) to a single variable is sufficient. I do not see a need why in those cases we need execution order on top of exclusive access.

---

<div class="post-metadata">

**Author:** ![robert.berger](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/robert.berger/32/4739_2.png) [@robert.berger](https://forums.freertos.org/u/robert.berger)\
**Post date:** [November 4, 2025, 12:40pm UTC](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685/20 "2025-11-04T12:40:00Z")

</div>

As usual, the answer is - it depends, and I tend to be a bit overcautious. Actually, one attendee of my workshops told me that all the programmers on this planet assume that 32-bit operations on a 32-bit CPU just work out of the box. No, they don’t.

Say, we have 2 variables:

```auto
  volatile uint32_t uintCounter = 0;
  atomic_uint_least32_t uint_least32CounterAtomic = 0;

```

Now make 2 tasks, which increment these variables. Something like this:

```auto
void vTask2( void *pvParameters )
{
const char *pcTaskName = "Task 2:";
volatile unsigned long ul;

	/* As per most tasks, this task is implemented in an infinite loop. */
	for( ;; )
	{
		uintCounter++;
		uint_least32CounterAtomic++;
#if PRINTOUTS == 1
		/* Print out the name of this task. */
		if (uintCounter != uint_least32CounterAtomic){
		vPrintStringAndNumber( pcTaskName, uintCounter );
		vPrintStringAndNumber( pcTaskName, uint_least32CounterAtomic );
        #if HANG_ON_NEQ > 0
			for(;;);
        #endif
		}
#endif
		taskYIELD();
	}
}

```

I was surprised how quickly they are not equal.

You can imagine that we can come up with many interesting scenarios, where it’s fatal to ignore the order of execution. E.g. writing to 3 registers in the right order - Set the bit to start the PWM at the end.

[Next page](https://forums.freertos.org/t/shared-resource-between-task-and-isr/24685.md?page=2)
