I have couple questions regarding setting signals to inactive threads using RTX and CMSIS. Please see the example code below:
osThreadId thread_id = osThreadCreate(osThread(thread_body), NULL); /* set thread active */
osThreadTerminate(thread_id); /* set thread inactive */
osSignalSet(thread_id, 1); /* set signal to inactive thread */
osThreadCreate(osThread(thread_body), NULL); /* set same thread active again */
void thread_body (void const * arg) { osSignalWait(1, 0); /* is the signal set? */ }
Questions: 1) The signal is set while the thread is inactive. What is the effect of this? 2) In the thread_body function, will the signal be set?
Thank you
That is considered erroneous code. Calling Terminate is very similar to calling free. You may still have a ThreadId pointer, but what it points to is no longer allocated to any thread so the data should be considered to have no meaning. The behavior is entirely undefined.
Actual answers to the questions:
1) Sets Signal for now terminated thread, does nothing as task is not waiting for signals Sets Signal for a thread that has the same threadId as the old Thread. Fails to Set anything for various reasons.
2) No. Events are cleared on each Thread Creation. There are no cases that this will be set for a newly created thread.
Hi Robert,
Thanks for your response. Follow up question:
How should one handle a case where say thread ‘A’ has saved the thread id of thread ‘B’ and is now performing a task. Thread ‘B’ is in the WAITING state waiting for a signal to be set by thread ‘A’. Before thread ‘A’ completes the task, thread ‘B’ is terminated via another thread. When thread ‘A’ completes the task and is now ready to set the signal to thread ‘B’, how can thread ‘A’ know that thread ‘B’ is terminated and skip setting the signal?
CMSIS does not seem to provide a direct method to check if a thread is in the INACTIVE state or not. I suppose it could be done indirectly by calling osThreadGetPriority and it would return osPriorityError if the thread was terminated?
Thanks,
Ben
You should think twice about terminating threads.
Terminating a thread means you have something else kill the thread without any way for the thread to properly synchronize/finish. That's almost always a bad idea - the only situation where it might actually be meaningful would be if it's a debugger that wants to kill a thread.
A properly written thread (that you need to be able to end) should have a way for you to signal that you want it to end. Then it can properly deallocate resources etc before ending.
Next thing - if you are ending a thread that you actually want to send signals to, then you have an error in your logic. You should only end a thread that you do know you will not need again. Or maybe that you know you will not need in a siginificant amount of time. So there shouldn't really be any other threads that tries to signal it because that would imply that the thread is still needed and so shouldn't have been ended in the first place.
If you can't keep track of what threads are existing and which threads have been ended, then that would indicate that your design is too complicated. So better take a closer look at the interactions between the threads and simplify the design until you know about who all producer/consumer or publisher/subscriber relations and their required life cycles.
Hello Per,
Thank you for your response. I believe I am terminating threads in a simple and controlled manor. Terminating threads solves a difficult problem for me. Let me explain my problem.
My application controls multiple stepper motors (among other things) that run simultaneously. I have a stepper thread that controls the steppers and receives commands from client threads via a command mail message. The command mail message contains the thread id and a specified signal mask from the client thread. The client thread will, at times, pend forever on this signal to be set or pend forever on other os events.
The problem arises when an event occurs requiring the system to stop immediately. This stop event is asynchronous to the client and stepper threads. If the client thread is pending forever on a specific os event, how could it be ‘notified’ of this stop event? The client thread has many states that pend forever on many different os events or os delays of some value. The system has to respond immediately to the stop event. To do this, every state in the client thread would need to poll for this stop event and could not pend forever. It seems to me this polling in every state would add a lot of code, would be error prone, a waste of CPU cycles and does not utilize the power of the RTOS.
I solve this problem by handling the stop event in a separate thread. My system is designed such that only one client thread is active at a time. This stop event thread will immediately terminate the one client thread. The client thread can be in any state pending on any os event. The stop event thread handles any cleanup of resources such as sending a stop command to the stepper thread. At this time though, it is possible that the stepper thread is still performing a command sent by the now terminated client thread. But the response from the stepper thread to the client thread (in the form of setting a signal) is now meaningless and it does not matter if it comes or not.
I think the design is quite simple and is very efficient since the client thread can pend forever in any state on any os event (no polling code, no wasted CPU cycles). I am not losing track of active/inactive threads. I am simply using methods provided by CMSIS. The signal being set to the terminated thread is not a logic error. The system is designed such that this is a “don’t care” situation. If the call to osSignalSet with a terminated thread id has no effect, then there is no issue. If there is an undesirable/undefined effect, is there a way to check that a thread is inactive and the call to osSignalSet could then be skipped?
Or is there a better solution to this problem?
Regards,
A common way is to let a thread wait for multiple events. So either an "action" event or a "quit" event.
Same can be done when waiting on a mailbox: - set a global flag "please thread x end" - send a dummy mail to the thread - whenever the thread picks up a mail it checks the "end" flag
Another alternative is to have timeout on all wait calls, allowing the individual threads to regularly poll other data before restarting the waits.
Lots of code constructs will be impossible or at least very difficult to read/use if a thread may be killed by outside sources. And other parts of the code will have to have significant internal knowledge about the inner workings of the thread to attempt "garbage collect" of allocated resources and restore of data structures and hardware to well defined states.
How do you draw a state diagram, when some outside force may kick you out of the state diagram at an arbitrary state - or even in the middle of a state-changing action?
How do you expect to ever manage a full coverage analysis of your code validating every single code path, when there is an arbitrary asynchronous action that may hit the individual threads?
Another thing is that an thread priority change may give unexpected new failures depending on if the thread that kills other threads have higher or lower priority than the thread(s) that are about to be killed. How can you graphically depict this and make sure any developer who picks up the code will be able to spot these dangers?
Think about a program using C++ with objects having constructors and destructors. If the OS has preemptive task switching and the thread gets killed after an object has been constructed but before it gets destructed, then the destructor will not be called. How would a developer be able to spot this?
Think about yourself - you want to perform actions based on received stimuli. You wouldn't want some external force to be able to magically teleport you into a different location at arbitrary times without your control. If you are on the toilet and it knocks on the door - do you want to finish your "critical section" or do you want to be forcibly and instantly teleported to the outside of the door?
Per,
Again valid points. I have some thinking to do about my architecture. I would like to say though, that I believe my architecture handles “knocks on the door” just fine. Critical sections are completed and the door is answered. The case I’m talking about is not a knock on the door, it’s a fire. If I’m on the toilet in the middle of a “critical section” and all of a sudden theres a life threatening fire, I’d gladly be magically teleported to a different location and will deal with the clean up later.
If you are doing a panic stop after getting a sensor error or someone have pressed a stop button, then you could kill all threads. But you then shouldn't expect to be able to recover from that state. So have the panic code rewrite the state of every I/O pin of the chip to turn off power, short-circuits motors as electrical breaks etc and then wait for an operator to reset the device and then potentially on reboot wait for a key lock activation before limping back to "home position" to do a full self-test before you are ready to start up normal operation again.
Any time you kill a thread, you are violating any known/documented state information for that thread and potentially an unknown number of global variables/hardware. And if the kill comes from a thread of same or higher priority so the kill need not happen in a wait function, you might also violate code-generation or logic rules of the programming language or the runtime library.
If you have any plan at all for returning to normal operation without rebooting, then you really shouldn't kill threads but should spend the time/code to teach them how to always respond to ordered thread-stop events.
Think again about that magical teleportation. It would be "safe" if it always teleported you to a known safe state. So you always ended up in a bed at a safe place. If it instead only manages a horizontal translation, and you happened to start from the eight floor of a building, you might end up with a quite long fall when you got teleported into thin air eight floors above the "rallying point". Killing a thread leaves you in an unknown state where you do not know what is needed to recover. It is a "crash out" function, where only a reset has a contractual obligation to return you to a known state.
I have found a complete and elegant solution to the problem of “waking up” a thread that can pend on several different os events - the CMSIS osWait function. If this function were used for pending, it would be simple to send an asynchronous “halt event” to a thread no matter what its pending on, even a timeout. The thread could then handle the event and any necessary cleanup. No terminating of threads required.
Only problem is, the CMSIS osWait function is optional and RTX doesn’t support it. Why doesn’t RTX support osWait? This seems like an extremely useful function. Can it be added?