Let Task B use heap allocated resourcs of Main Task good practice?

My question is about good coding practice. Consider the following code architecture that I have right now:


The functions of the main task (task A) create task B through the API provided by the submodule translation unit. This init_task_b function heap allocates space for the info struct, creates the task B and stores its handle along with some additional information in the info struct. The structs address is then returned to task A functions where it is stored in a static variable. At the same time in the task_b_init-function, the structs address is passed on to task B, where task B uses some of the information stored in the info-struct to operate.

The question is: Is this good practice? Because both tasks, A and B use the same struct, it could happen that it gets deleted by task A and task B is left with a nullpointer. However, this shouldn’t happen as the struct is only to be modified by task B API-Functions. Still… I’m left wondering. What do you think?

EDIT: I just read the linux kernel style guide where it was hinted that using an opaque struct (struct keyword typedefed away) is only allowed for use in accessor functions, to so say “force” the user to use the accessor functions. In the case of my info-struct, would this make the above architecture valid?

I think it’s ok to share information between tasks this way.
I’d avoid to dynamically create/delete tasks and also shared data during runtime because this makes a robust design (no resource leaks, dangling pointers, etc.) more complicated.

Thanks for your answer! By avoiding creating / deleting tasks at runtime you mean after the esp has initialized?

I have now implemented it in a way where the handle-struct that is passed to the outside is linked with an internal data struct that contains the tasks data. In this way, even if the handle gets deleted, the data struct stays alive. Then I implemented a cleanup function that deletes the task and also the task & handle data.

I mean I usually only create tasks but don’t delete them later on. There might be rare use cases creating/deleting tasks dynamically where e.g. 2 tasks are needed mutually exclusively and you’re very short of RAM. Even this is not straight forward because if a task deletes itself the deletion is deferred and done by the idle task later on and you don’t know exactly when its resources are really freed.
Task deletion is only synchronous/done immediately if a task deletes another task using its handle. But the deleting task needs to know when it’s safe/suitable to delete the other task and you might need some extra synchronization for that.
However, taking care that the shared data at least remains valid as long as it’s in use by a task is necessary and a good approach.

Good remark thank you. I integrate cleanup functions because it helps me in getting my code design straight. I don’t actually have to delete the task. But I was just wondering: What happens when I delete a task during an Idle phase, e.g. during QueueReceive()? Will that cause an error?

I think this would be ok.

Remove a task from the RTOS kernels management. The task being deleted will be removed from all ready, blocked, suspended and event lists.