线程和信号的一些介绍 (signal(7))
信号处置是每个进程的属性:在多线程应用程序中,特定信号的处置对所有线程都是相同的。
进程导向的信号:进程导向的信号是针对整个进程(并因此等待)的信号。进程导向的信号可以传递给当前没有阻塞信号的任何一个线程。如果多个线程的信号被解除阻塞,那么内核会选择一个任意线程来传递信号。
线程导向信号:线程导向信号是针对特定线程的信号。该集合将由未决的进程导向信号集和调用线程的未决信号集的并集组成。
您可以配置您的程序来告诉如何处理信号。你可以忽略它们(很少有不能忽略的),注册一个信号处理程序,当接收到特定信号时将调用它(asynchronous),或者阻止它稍后处理它(synchronous)。
来到你的案子,
“问题是:信号处理函数运行时线程会发生什么?”
信号被传递给配置为接收它的任何线程一次。异步处理信号的线程停止它正在做的任何事情并跳转到配置的信号处理程序。其余线程中的执行流程不受影响。
如果线程继续运行它们的工作,有没有办法在调试处理程序工作时冻结它们?
没有标准的方法来做到这一点。您需要建立自己的机制来实现这一点。
为了进一步研究,需要明确调试处理程序的执行位置。在每个线程或main() 或特定线程中?
编辑
假设main() 实现了日志功能,下面尝试实现相同的基本最小值。添加了注释,使您能够遍历代码并理解实现。
#define THREAD_MAX_COUNT 100
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int debug;
sigset_t debug_mask;
pthread_t main_tid;
void* thread_func(void* th_data)
{
/* .... */
for ( ; ; ) {
if (debug) { // If debug procedure starts
printf("Freezing %d\n", *((int*) th_data));
pthread_kill(main_tid, SIGRTMIN); // Notify the main thread about the thread's freeze.
int signo;
sigwait(&debug_mask, &signo); // Wait till logging is done. main() will signal once it is done.
printf("Resuming %d\n", *((int*) th_data));
}
/* ... */
}
return NULL;
}
int main() {
/* Block SIGINT SIGRTMIN*/
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGINT);
sigaddset(&sigmask, SIGRTMIN);
pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
/* Set debug variables */
debug = 0;
sigemptyset(&debug_mask);
sigaddset(&debug_mask, SIGRTMIN);
main_tid = pthread_self();
/* Get signalfd for SIGINT */
int sigfd = signalfd(-1, &sigmask, 0);
struct signalfd_siginfo sigbuf;
/* Select variable initializations */
fd_set rd_set, tr_set;
FD_ZERO(&rd_set);
FD_SET(sigfd, &rd_set);
int td_count = 0;
pthread_t tids[THREAD_MAX_COUNT];
for ( ; ; ) {
/* Wait for signal */
tr_set = rd_set;
select(sigfd + 1, &tr_set, NULL, NULL, NULL);
if (FD_ISSET(sigfd, &tr_set)) {
/* Read the pending signal */
read(sigfd, &sigbuf, sizeof(sigbuf));
/* Start logging */
debug = 1;
int signo;
for (int count = 0; count < td_count; count++) {
/* Wait for all threads to freeze */
sigwait(&debug_mask, &signo);
}
printf("Logging...\n");
sleep(3);
/* End logging and resume threads */
debug = 0;
for (int count = 0; count < td_count; count++)
pthread_kill(tids[count], SIGRTMIN);
/* Note below code is for testing purpose; Creates new thread on each interruption */
int* td_data = malloc(sizeof(int));
*td_data = td_count;
pthread_create(tids + td_count, NULL, thread_func, td_data);
td_count++;
}
}
return 0;
}
终端会话:
$ gcc SO.c -lpthread
$ ./a.out
^CLogging...
^CFreezing 0
Logging...
Resuming 0
^CFreezing 0
Freezing 1
Logging...
Resuming 0
Resuming 1
^CFreezing 0
Freezing 1
Freezing 2
Logging...
Resuming 1
Resuming 0
Resuming 2
^CFreezing 2
Freezing 3
Freezing 1
Freezing 0
Logging...
Resuming 1
Resuming 3
Resuming 2
Resuming 0
^CFreezing 1
Freezing 4
Freezing 3
Freezing 0
Freezing 2
Logging...
Resuming 1
Resuming 2
Resuming 0
Resuming 4
Resuming 3
^CFreezing 3
Freezing 0
Freezing 4
Freezing 2
Freezing 5
Freezing 1
Logging...
Resuming 0
Resuming 1
Resuming 2
Resuming 5
Resuming 3
Resuming 4
^\Quit (core dumped)