最好的方法是阻止除一个线程以外的所有线程。

huangapple go评论73阅读模式
英文:

What is the best way to block all threads except one?

问题

我正在处理一个项目,在其中需要在某个线程开始执行时阻止所有线程。我考虑过使用线程标志,但我认为这将涉及添加检查到所有线程。我还考虑过使用互斥锁来阻止所有线程,除了我需要执行/独占处理器的关键线程。我之所以还没有使用互斥锁,是因为我读到它只涉及资源,如果它们与互斥锁没有关联,一些线程仍然会继续执行,但我可能误解了这一点。

您能告诉我我的互斥锁方法是否正确,或者是否应该使用其他方法吗?

编辑:我在STM32H753芯片上使用Keil RTX 5/CMSIS RTOS 2。

谢谢

英文:

I am working on a project where I need to block all threads when a certain thread starts execution. I have considered using thread flags, but I believe this would involve adding checks to all the threads. I have also considered using a mutex to block all threads except the critical thread which I need to execute/have sole control of the processor. The reason why I haven't yet used a mutex is because I have read that it only relates to resources and that some threads would still continue to execute if they are not linked to the mutex, however I may have misunderstood this.

Could you please tell me if my approach to the mutex idea is correct or if I should use another method?

Edit: I am using Keil RTX 5/CMSIS RTOS 2 on the STM32H753 chip

Thanks

答案1

得分: 3

CMSIS RTOS具有一对函数osKernelLock()osKernelUnlock() - 动态修改线程优先级或使用互斥锁是不必要的,而且可能不明智。

任何其他RTOS都将具有类似的_临界区_ API。

请注意,这仅阻止任务上下文切换;它不会阻止中断运行。这通常是可取的,但如果您想要阻止它,您可以简单地使用_disable_irq()/_enable_irq()来禁用所有中断。这将阻止任务切换_和_中断。

禁用中断是一种粗暴的方法,对系统的实时行为产生更大的影响,甚至比调度程序锁定还要大。通常只应在非常短的时间内执行(就像调度程序锁定一样)。

英文:

The CMSIS RTOS has a pair of functions osKernelLock() and osKernelUnlock() - dynamically modifying thread priorities or using mutexes is unnecessary and probably ill-advised.

Any other RTOS will have similar critical section API.

Note that this only prevents task context switching; it does not prevent interrupts from running. This is normally desirable, but if you want to prevent that, you can simply disable all interrupts using _disable_irq()/_enable_irq(). That will prevent task switched and interrupts.

Disabling interrupts is brute-force and has a greater impact on the real-time behaviour of your system that even a scheduler lock. Generally it should be done only for very short periods (as should scheduler locking).

答案2

得分: 0

你现在使用的是什么RTOS?我会假设你正在使用基于优先级的RTOS。

不要在线程标志或互斥体上添加另一个调度机制。只需使用您已经有的调度程序。

如果您希望一个线程独占运行,那么将该线程设置为最高优先级线程。RTOS调度程序将运行准备运行的最高优先级线程。如果您的线程具有最高优先级且不会自己阻塞,那么其他线程将不会运行。在CMSIS-RTOS中,您可以使用osThreadSetPriority()更改线程的优先级。

英文:

What RTOS are you using? I'll assume you're using a priority based RTOS.

Don't layer another scheduling mechanism with thread flags or a mutex. Just use the scheduler that you already have.

If you want one thread to run exclusively, then make that thread the highest priority thread. The RTOS scheduler will run the highest priority thread that is ready to run. If your thread is highest priority and doesn't block itself, then the other threads will not run. In CMSIS-RTOS you can change a thread's priority with osThreadSetPriority().

答案3

得分: 0

不要直接从用户代码更改任务的优先级。大多数RTOS提供API,可以通过这些API来实现任务优先级的管理,但这种做法不佳,因为它会引发更多问题,而不是解决问题。唯一的例外是某些RTOS函数在内部执行此操作(例如,使用优先级继承来避免某些多任务问题的互斥体)。

我猜你想在系统的启动阶段或其他非常特殊的运行阶段内有更长的关键部分。否则,你应该真正听取@Clifford的评论并质疑你的优先级分配和任务分解

如果你只需要在初始化/启动阶段内有这种顺序的时间段,那么这是一个可以通过良好的任务设计实现的典型情况。在这种情况下,你需要的是运行级别管理

运行级别管理

实现这一点的最简单方法是在你的RTOS之上编写一个小型库,使用两个计数信号量资源:
一个是用于当前运行级别,另一个是用于下一个运行级别。
当进入一个运行级别时,信号量将被填充为需要受运行级别管理控制的任务数量。
每个等待处理特定运行级别的任务都试图从当前运行级别信号量中获取其令牌。
当任务完成其运行级别部分后,它会访问下一个级别信号量,这时该信号量将不可用。

在填充运行级别管理配置之前,你可以绘制一个顺序图来查看任务必须等待其他任务的原因。通常情况下,对于每个任务,只有少数运行级别是相关的 - 并且对于每个运行级别,相关任务的集合可能也很小。因此,你可能希望添加一个像WaitForRunlevelNumber(N)这样的小助手函数,其中包含一个自动处理那些不相关的运行级别的循环。

运行级别管理必须在需要显式同步的所有阶段都完成后结束。然后,所有任务都可以自由运行。有时,如果低优先级的任务已经完成了所有关键阶段,你可能希望更早地释放它们。然后,维护的任务数量可能会从一个运行级别减少到下一个运行级别。

英文:

Don't change priorities of your tasks directly from your user code. Most RTOSes provide APIs that enable us to do this, but it is bad style since it spawns more problems than it will solve. An exception is when certain RTOS functions to this internally (e.g, mutexes with priority inheritance to avoid certain multi-task issues).

I guess you want to have longer critical section only during the power-up phase of your system, or another very special phase of its runtime. Otherwise, you should really listen to @Clifford's comment and question your priority assignments and task decomposition.

If you need that sequential period only during init/power-up phase, this is a typical situation that is possible with good task design, too. In that case, what you need is a runlevel management.

Runlevel Management

The simplest way to implement this is to write a little library on top of your RTOS, using two counting semaphore resources:
One is for the present runlevel, the other for the next one.
When a runlevel is entered, the semaphore is filled as many tokens as there are tasks that must be under control of the runlevel management.
Every task waiting to process a given runlevel is trying to get its token from the current-runlevel semaphore.
When the task has finished its runlevel part, it accesses the next-level semaphore, which will be unavailable at that time.

Before populating the runlevel management configuration, you can draw yourself a
sequence diagram
to check at which points, tasks must wait for others for whatever reason.
Usually for every task, only few of the runlevels are relevant - and per runlevel, the set of relevant tasks may be small too.
Therefore you may want to add a little helper function like WaitForRunlevelNumber(N) with a loop that automatically deals with those runlevels that aren't relevant.

Runlevel management must finish if all phases that require explicit synchronisation are finished.
Then, all tasks are released into freedom.
Sometimes, you want to release low-priority tasks earlier if they have finished all critical phases yet.
Then the number of tasks maintained may decrease from one runlevel to the next.

huangapple
  • 本文由 发表于 2020年1月6日 19:17:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611143.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定