需要知道如何中断所有 pthreads
need to know how to interrupt all pthreads
在 Linux 中,我正在模拟一个嵌入式系统,该系统有一个线程可以将消息传送到外部世界。如果某个线程检测到无法解决的问题,我的目标是停止其轨道上的所有其他线程(留下有用的堆栈跟踪)并只允许消息传递线程继续。所以在我的仿真环境中,我想 "pthread_kill(tid, SIGnal)" 每个 "tid"。 (我有一个列表。我正在使用 SIGTSTP。)不幸的是,只有一个线程收到信号。 "sigprocmask()" 无法取消屏蔽信号。这是我当前的(非工作)处理程序:
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
我确认所有 pthread_kill() 都已被调用,但只有一个线程在堆栈跟踪中具有处理程序。这能做到吗?
这是不可能的。问题是你停止的一些线程可能持有你想要继续的线程 运行 需要的锁,以便继续取得进展。完全放弃这个想法。相信我,这只会让你很痛苦。
如果您确实必须这样做,请让所有其他线程在已知的安全位置调用条件屈服点,在这些地方它们不持有可以阻止任何其他线程到达其下一个条件屈服点的锁。但这是 非常 很难做到正确并且很容易出现死锁,我强烈建议不要尝试。
这个最小的示例似乎以您想要的方式运行 - 除了主线程之外的所有线程最终都在等待 wait_until_death()
:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#define NTHREADS 10
pthread_barrier_t barrier;
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
void *thread_func(void *arg)
{
pthread_barrier_wait(&barrier);
for (;;)
pause();
}
int main(int argc, char *argv[])
{
const int thread_signal = SIGTSTP;
const struct sigaction sa = { .sa_handler = wait_until_death };
int i;
pthread_t thread[NTHREADS];
pthread_barrier_init(&barrier, NULL, NTHREADS + 1);
sigaction(thread_signal, &sa, NULL);
for (i = 0; i < NTHREADS; i++)
pthread_create(&thread[i], NULL, thread_func, NULL);
pthread_barrier_wait(&barrier);
for (i = 0; i < NTHREADS; i++)
pthread_kill(thread[i], thread_signal);
fprintf(stderr, "All threads signalled.\n");
for (;;)
pause();
return 0;
}
请注意,不需要在 wait_until_death()
中解锁信号:信号掩码是针对每个线程的,并且不会再次向正在执行信号处理程序的线程发送信号。
大概问题在于您如何安装信号处理程序或设置线程信号掩码。
在 Linux 中,我正在模拟一个嵌入式系统,该系统有一个线程可以将消息传送到外部世界。如果某个线程检测到无法解决的问题,我的目标是停止其轨道上的所有其他线程(留下有用的堆栈跟踪)并只允许消息传递线程继续。所以在我的仿真环境中,我想 "pthread_kill(tid, SIGnal)" 每个 "tid"。 (我有一个列表。我正在使用 SIGTSTP。)不幸的是,只有一个线程收到信号。 "sigprocmask()" 无法取消屏蔽信号。这是我当前的(非工作)处理程序:
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
我确认所有 pthread_kill() 都已被调用,但只有一个线程在堆栈跟踪中具有处理程序。这能做到吗?
这是不可能的。问题是你停止的一些线程可能持有你想要继续的线程 运行 需要的锁,以便继续取得进展。完全放弃这个想法。相信我,这只会让你很痛苦。
如果您确实必须这样做,请让所有其他线程在已知的安全位置调用条件屈服点,在这些地方它们不持有可以阻止任何其他线程到达其下一个条件屈服点的锁。但这是 非常 很难做到正确并且很容易出现死锁,我强烈建议不要尝试。
这个最小的示例似乎以您想要的方式运行 - 除了主线程之外的所有线程最终都在等待 wait_until_death()
:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#define NTHREADS 10
pthread_barrier_t barrier;
void
wait_until_death(int sig)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
for (;;)
pause();
}
void *thread_func(void *arg)
{
pthread_barrier_wait(&barrier);
for (;;)
pause();
}
int main(int argc, char *argv[])
{
const int thread_signal = SIGTSTP;
const struct sigaction sa = { .sa_handler = wait_until_death };
int i;
pthread_t thread[NTHREADS];
pthread_barrier_init(&barrier, NULL, NTHREADS + 1);
sigaction(thread_signal, &sa, NULL);
for (i = 0; i < NTHREADS; i++)
pthread_create(&thread[i], NULL, thread_func, NULL);
pthread_barrier_wait(&barrier);
for (i = 0; i < NTHREADS; i++)
pthread_kill(thread[i], thread_signal);
fprintf(stderr, "All threads signalled.\n");
for (;;)
pause();
return 0;
}
请注意,不需要在 wait_until_death()
中解锁信号:信号掩码是针对每个线程的,并且不会再次向正在执行信号处理程序的线程发送信号。
大概问题在于您如何安装信号处理程序或设置线程信号掩码。