根据优先级强制Win32线程调度到定义的序列

时间:2010-11-18 18:54:44

标签: c multithreading winapi visual-studio-2010

4 个答案:

答案 0 :(得分:5)

如果您需要自己安排,那么您可以考虑使用fibers而不是线程。光纤类似于线程,因为它们是可执行代码的单独块,但是光纤可以在用户代码中调度,而线程仅由OS调度。单个线程可以托管和管理多个光纤的调度,光纤甚至可以相互安排。

答案 1 :(得分:1)

首先,您为线程使用了哪些优先级值?

如果将高优先级线程设置为THREAD_PRIORITY_TIME_CRITICAL,它应该立即运行 - 只有与实时进程关联的线程才会具有更高的优先级。

其次,你怎么知道暂停和恢复没有立即发生?你确定这是问题吗?

您不能强制线程在外部等待某些内容而不挂起线程来注入等待代码;如果SuspendThread不适合您,那么这无济于事。

最接近信号的可能是QueueUserAPC,它将安排回调在下次线程进入“可警告的等待状态”时运行,例如,致电SleepExWaitForSingleObjectEx或类似。

答案 2 :(得分:1)

@Anthony W - 感谢您的建议。我正在运行模拟THREAD_PRIORITY_ABOVE_NORMAL的实时任务的Win32线程,以及在THREAD_PRIORITY_HIGHEST运行伪中断处理程序和tick中断生成器的线程。暂停的线程我正在更改为THREAD_PRIORITY_IDLE,以防有任何不同。我刚刚尝试过使用THREAD_PRIORITY_TIME_CRITICAL的建议,但遗憾的是它没有任何区别。

关于你的问题,我确定暂停和恢复不会立即发生问题 - 不,我不是。在我不熟悉的环境中,这是我最好的猜测。关于暂停和恢复工作失败的想法源于我在任务产生时的观察。如果我调用yield(信号[使用Win32事件]更高优先级的Win32线程切换到下一个实时任务)我可以在yield之后放置一个断点,并在更高优先级的断点之前命中线。目前还不清楚是否发生信号事件和更高优先级任务运行的延迟,或暂停线程和线程实际停止运行的延迟是否导致这种情况 - 但是行为是明确的。这是使用信号量握手修复的,但是对于由滴答中断引起的抢占无法做到这一点。

我知道模拟没有按预期运行,因为检查实时任务调度顺序的一组测试失败了。调度程序总是有问题,或者测试有问题,但是测试将运行数周而不会在真正的实时目标上失败,所以我倾向于认为测试和调度程序都没问题。一个很大的区别是实时目标的滴答频率是1毫秒,而在Win32模拟目标上它是15毫秒,即使在那时也有很多变化。

@Remy - 我今天已经完成了很多关于光纤的阅读,我的结论是,为了在协作模式下模拟调度程序,它们将是完美的。但是,据我所知,它们只能由光纤自己调度,调用SwitchToFiber()函数。可以使一个线程在计时器上阻塞或睡眠,以便它定期运行,有效地抢占当时正在运行的光纤吗?从我所看到的答案是肯定的,因为阻塞一根光纤将阻止在线程中运行的所有光纤。如果它可以工作,那么周期性执行的光纤是否可以调用SwitchToFiber()函数来选择下一个光纤运行,然后再睡一段固定的时间?我再次认为答案是否定的,因为一旦它切换到另一个光纤,它将不再执行,因此实际上不会调用Sleep()函数,直到下一次执行光纤切换回它。如果我对光纤的工作方式有错误的认识,请在此纠正我的逻辑。

我认为如果周期性功能可以保留在自己的线程中,与执行光纤的线程分开,那么它可以工作 - 但是(再次从我读过的内容)我不认为一个线程可以影响执行纤维在不同的线程中运行。如果你能在错误的情况下纠正我的结论,我将不胜感激。

答案 3 :(得分:1)

[编辑] - 比下面的黑客更简单 - 似乎只是确保在同一CPU核心上运行的所有线程也解决了问题:o)毕竟。唯一的问题是CPU运行率接近100%,我不确定热量是否会对它造成损害。 [/编辑]

AHAA!我想我有一个解决方案 - 但它很难看。丑陋虽然保留在端口层。

我现在所做的是在每次创建线程时存储线程ID以运行任务(为每个创建的实时任务创建Win32线程)。然后我添加了下面的函数 - 使用跟踪宏调用。可以将跟踪宏定义为执行您想要的任何操作,并且已经证明在这种情况下非常有用。以下代码中的注释说明。模拟并不完美,所有这一切都是正确的线程调度,当它已经偏离实时调度时,我宁愿它不会出错,但是跟踪宏的定位使代码包含这个解决方案通过了所有测试:

void vPortCheckCorrectThreadIsRunning( void )
{
xThreadState *pxThreadState;

    /* When switching threads, Windows does not always seem to run the selected
    thread immediately.  This function can be called to check if the thread
    that is currently running is the thread that is responsible for executing
    the task selected by the real time scheduler.  The demo project for the Win32
    port calls this function from the trace macros which are seeded throughout 
    the real time kernel code at points where something significant occurs.
    Adding this functionality allows all the standard tests to pass, but users
    should still be aware that extra calls to this function could be required
    if their application requires absolute fixes and predictable sequencing (as
    the port tests do).  This is still a simulation - not the real thing! */
    if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
    {
        /* Obtain the real time task to Win32 mapping state information. */
        pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );

        if( GetCurrentThreadId() != pxThreadState->ulThreadId )
        {
            SwitchToThread();
        }
    }
}