如何挂起另一个线程(不是当前线程)?

时间:2010-02-05 16:56:56

标签: linux multithreading pthreads

我正在尝试实现微控制器的仿真。此仿真并不意味着对一个特定的微控制器进行时钟周期精确表示,而是检查代码的一般正确性。

我想到了一个执行普通代码的“主线程”和一个执行ISR代码的第二个线程。每当需要运行ISR时,ISR线程就会挂起“主线程”。

当然,我想要一个阻止中断的功能。 我想用一个互斥体来解决这个问题,ISR线程只要执行ISR代码就会保留,而主线程只要“中断被阻塞”就会保留它。

POR(上电复位)可以通过暂停但杀死主线程(以及启动执行POR功能的新线程)来实现。

Windows API提供必要的功能。 但似乎不可能使用posix线程(在linux上)执行上述操作。

我不想改变实际的硬件独立微控制器代码。因此,插入任何内容以检查待处理的中断都不是一种选择。

在非性能良好的点接收中断是可取的,因为这也会发生在微控制器上(除非阻止中断)。

有没有办法在Linux上挂起另一个线程? (我认为,调试器必须以某种方式使用该选项。)

请不要告诉我这是一个坏主意。我知道在大多数情况下都是如此。但主代码不使用标准库或锁/互斥锁/信号量。

6 个答案:

答案 0 :(得分:11)

SIGSTOP不起作用 - 它总是停止整个过程。 相反,您可以使用其他一些信号,例如SIGUSR1用于暂停,SIGUSR2用于恢复:

// at process start call init_pthread_suspending to install the handlers
// to suspend a thread use pthread_kill(thread_id, SUSPEND_SIG)
// to resume a thread use pthread_kill(thread_id, RESUME_SIG)

#include <signal.h>

#define RESUME_SIG SIGUSR2
#define SUSPEND_SIG SIGUSR1

static sigset_t wait_mask;
static __thread int suspended; // per-thread flag

void resume_handler(int sig)
{
    suspended = 0;
}

void suspend_handler(int sig)
{
    if (suspended) return;
    suspended = 1;
    do sigsuspend(&wait_mask); while (suspended);
}

void init_pthread_suspending()
{
    struct sigaction sa;

    sigfillset(&wait_mask);
    sigdelset(&wait_mask, SUSPEND_SIG)
    sigdelset(&wait_mask, RESUME_SIG);

    sigfillset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = resume_handler;
    sigaction(RESUME_SIG, &sa, NULL);

    sa.sa_handler = suspend_handler;
    sigaction(SUSPEND_SIG, &sa, NULL);
}

我非常恼火地回答“你不应该暂停另一个线程,那是坏事”。 伙计们为什么你认为别人是白痴,不知道他们在做什么?想象一下,其他人也听说过死锁,而且在完全意识中,他们还想暂停其他线程。 如果你对他们的问题没有真正的答案,为什么要浪费你和读者的时间。

是的,IMO pthreads是非常短视的api,对POSIX来说是一种耻辱。

答案 1 :(得分:5)

Hotspot JAVA VM使用SIGUSR2为Linux上的JAVA线程实现挂起/恢复。

基于SIGUSR2的信号处理程序的过程可能是:

为SIGUSR2提供信号处理程序允许线程请求锁定 (已经被信号发送线程获得)。

这会挂起线程。

一旦挂起线程释放锁定,信号处理程序就可以 (并且会?)获得锁定。信号处理程序立即释放锁定 离开信号处理程序。

这将恢复该主题。

在开始实际处理ISR之前,可能需要引入一个控制变量以确保主线程在信号处理程序中。 (细节取决于是同步还是异步调用信号处理程序。)

我不知道,如果这正是它在Java VM中的完成方式,但我认为上述过程可以满足我的需要。

答案 2 :(得分:3)

不知怎的,我认为发送另一个线程SIGSTOP是有效的。

但是,编写一些涉及senaogires.mutexes和全局变量的线程通信要好得多。

你看,如果你在malloc()中挂起另一个线程,你调用malloc() - &gt;死锁。

我是否提到过很多C标准库函数,更不用说你使用的其他库了,会在你背后调用malloc()吗?

编辑:

嗯,没有标准库代码。也许使用来自信号处理程序的setjmp / longjump()来模拟POR和一个模拟中断的信号处理器。

对于那些让人失望的人:EDIT之后的内容接受了答案,这是一个不能在任何其他场景中使用的特定场景。

答案 3 :(得分:1)

Solaris具有thr_suspend(3C)调用,可以执行您想要的操作。是否有可能转向Solaris?

除此之外,你可能不得不做一些互斥和/或信号量的体操。问题是,只有在检查互斥锁时才会暂停,这可能是一个表现良好的点。根据您实际想要完成的任务,现在可能需要这样做。

答案 4 :(得分:1)

让主线程执行ISR更有意义 - 因为这就是真实控制器的工作原理(大概)。如果两个中断都挂起,并且当前启用了中断,则只需在每个模拟指令之后进行检查 - 如果是,则模拟对ISR的调用。

仍然使用第二个线程 - 但它只是监听导致中断的条件,并将相关的中断标记为挂起(对于稍后拾取的另一个线程)。

答案 5 :(得分:0)

使用pthread_kill(3)和SIGUSR1,SIGUSER2信号的解决方案是一个很好的解决方案,但仍然可能导致并发问题。 有没有办法在安全点挂起所有线程(主线程除外),即在挂起线程时不应该获得任何锁定或不在系统调用中运行?