0

My question relates to

What is disadvantage of calling sleep() inside mutex lock?

I have a similar situation, and I am not quite understanding why sleeping while holding a mutex is such a no-no. What are the consequences, in terms of deadlock, starvation, correctness, etc, of doing this?

I have an embedded system, using an RTOS. That RTOS supports osDelay (sleep) and mutexes.

I have 2+ threads that may require access to an i2c bus peripheral in order to write to an eeprom device on that bus. There may be other devices on that same i2c bus.

A mutex is taken to ensure exclusive access to the i2c peripheral (and hence bus). During the period of holding that mutex, I have to delay 10ms between consecutive eeprom writes. This is just a requirement of the eeprom chip. eeprom reads don't require delays.

How can I achieve my hardware constraints WITHOUT 'delay inside mutex'?

Stuart
  • 37
  • 5
  • Well nobody can use the sleeping thread while its sleeping. Not sure how that affects the specifics of your situation but it might be safer to lock the mutex, schedule it to be unlocked at the appropriate time and then return, if that approach is possible. – Joe May 04 '22 at 22:04
  • https://stackoverflow.com/questions/30666183/i-want-to-sleep-while-holding-a-mutex – Iłya Bursov May 04 '22 at 22:09
  • Unsure what you mean by 'nobody can use the sleeping thread'. The sleep is required to allow the eeprom chip time to process the data I just sent it over i2c. If I have a lot of data for the eeprom, I want to do that all inside one mutex lock session. The alternative I guess is to sleep first, then acquire the mutex. This will require N mutex lock/unlock pairs though, for N distinct eeprom writes. – Stuart May 04 '22 at 22:18
  • There is a better design than allowing multiple threads to use a resource like a serial bus. Create a single thread that does all the i2c communications. The i2c thread waits on a message queue that receives requests from the other threads that want to use the bus. The i2c thread runs each request to completion before waiting for the next request. This design serializes the other threads' use of the bus and avoids the need for a mutex. ([Beyond the RTOS](https://www.youtube.com/results?search_query=beyond+the+rtos) part 1 describes the problem and part 2 describes the better design.) – kkrambo May 04 '22 at 22:48
  • Thanks. I did think about that solution. Alas for me, in a RAM-constrained environment, dedicating some RAM to yet another thread stack is an issue. Also, how does one communicate error conditions, at the i2c level, back to the original thread requesting the i2c service? – Stuart May 04 '22 at 23:21
  • Those videos are certainly useful, and I am conversant with the Active Object / Actor idiom. It seems well suited to the 'fire-and-forget' practice of writing data to say eeprom via i2c. The calling thread posts the data as a message onto a message queue managed by the actor, and the actor has exclusive access to the hardware. But how does data flow in the other direction? What happens when I want to read data from eeprom? How does the actor 'deliver results' to a calling thread? Futures?? – Stuart May 05 '22 at 00:23
  • There is probably no one-size-fits-all answer and it's hard to know what is right for your application. Perhaps the i2c thread posts the data to another message queue. Perhaps the thread that consumes the data is different from the thread that requested the data. Think of the received data as an event to be posted to some other active object. – kkrambo May 05 '22 at 13:41
  • The omission of mutexes is a worthy goal, I do like it. I agree with you that two message queues may be needed, one for writes and one for reads. They can both be hidden behind the i2c bus thread impl. What i like about this solution is that it leads to composable code. The i2c api as just needs the active object facade in front of it. In single-threaded apps, that facade is not needed. – Stuart May 05 '22 at 16:04
  • Think of a better design. You should not need to hold the I2C mutex for the 10ms EEPROM latency if you are not communicating with the EEPROM during that time. Release the resource, do the delay, require the resource. Simple. You could in fact run the I2C without a mutex at all. Simply have an I2C task and pass transaction requests to it via a queue, and take responses via a call-back (which might then put responses onto the users queue). By using a resource manager task, you do not need a mutex, so you avoid priority inversion and dead-lock issues and timing interactions. – Clifford May 09 '22 at 17:27

0 Answers0