当进程接收到信号时线程会发生什么?
What happens to threads when process receives signal?
我是 C 的新手,所以问题可能很愚蠢。
我正在编写操作从客户端发送的数据的套接字服务器。
当它获得连接时,它会创建将处理请求的线程。
它还定义了信号处理程序。当收到 SIGUSR1 时,它会将调试信息打印到日志文件中。
问题是:当信号处理函数为 运行?
时线程会发生什么
如果线程继续 运行 它们的工作,有没有办法在调试处理程序工作时冻结它们?
我试图在 pthreads(7) 的联机帮助页中找到答案,但此时还不明白。
抱歉,可能的术语不正确。
When SIGUSR1 is received it prints debug info to the logfile. The question is: what happens to threads when signal handling function is running?
进程中的一个线程(通常是 Linux 上的主线程 - 但不能保证或可移植假设)处理信号,而其他线程继续 运行1.
If threads continue running their jobs, is there a way to freeze them while debugging handler is working?
没有直接的方法可以实现这一目标。您可以实现一种机制,例如处理 SIGUSR1 的线程通知其他线程等待(例如使用条件变量),然后一旦处理完信号,它就可以通知其他线程继续。但我不推荐这样做,因为信号处理程序应该做尽可能小的功能。在信号处理程序中拥有复杂的功能通常被认为是不好的。您应该改为重新设计,以便其他线程不必停止(如果其他线程在记录调试信息时继续运行,会有什么问题?)。
1 处理这个问题的通常方法是使用专门的线程来处理信号。即阻止您感兴趣的信号并创建一个线程(在创建其他线程之前)来处理这些信号。 pthread_sigmask(3)
有一个如何操作的例子。
-
线程和信号的一些介绍(signal(7)
)
- 信号配置为per-process
信号处置是一个 per-process 属性:在多线程应用程序中,特定信号的处置对于所有线程都是相同的。
- 信号可能是process-directed或thread-directed
Process-directed 信号: process-directed 信号是针对(并因此等待)整个过程的信号。 process-directed 信号可以传递给当前未阻塞信号的任何一个线程。如果不止一个线程的信号被解除阻塞,那么内核会选择一个任意线程来传递信号。
Thread-directed 信号: thread-directed 信号是针对特定线程的信号。该集合将包含未决 process-directed 信号集和调用线程的未决信号集的并集。
- 异步和同步信号处理
您可以配置您的程序来告诉如何处理信号。你可以忽略它们(很少有不能忽略的),注册一个信号处理程序,当接收到特定信号时将调用它(asynchronous
),或者阻止它稍后处理它(synchronous
) .
针对您的情况,
"The question is: what happens to threads when signal handling function is running?"
信号被传送到配置为接收它的任何线程一次。异步处理信号的线程停止正在做的任何事情并跳转到配置的信号处理程序。其余线程中的执行流程不受影响。
If threads continue running their jobs, is there a way to freeze them while debugging handler is working?
没有执行此操作的标准方法。您需要建立自己的机制来启用此功能。
为了进一步研究,需要明确调试处理程序的执行位置。在每个线程或 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;
}
航站楼Session:
$ 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)
我是 C 的新手,所以问题可能很愚蠢。
我正在编写操作从客户端发送的数据的套接字服务器。 当它获得连接时,它会创建将处理请求的线程。
它还定义了信号处理程序。当收到 SIGUSR1 时,它会将调试信息打印到日志文件中。 问题是:当信号处理函数为 运行?
时线程会发生什么如果线程继续 运行 它们的工作,有没有办法在调试处理程序工作时冻结它们?
我试图在 pthreads(7) 的联机帮助页中找到答案,但此时还不明白。 抱歉,可能的术语不正确。
When SIGUSR1 is received it prints debug info to the logfile. The question is: what happens to threads when signal handling function is running?
进程中的一个线程(通常是 Linux 上的主线程 - 但不能保证或可移植假设)处理信号,而其他线程继续 运行1.
If threads continue running their jobs, is there a way to freeze them while debugging handler is working?
没有直接的方法可以实现这一目标。您可以实现一种机制,例如处理 SIGUSR1 的线程通知其他线程等待(例如使用条件变量),然后一旦处理完信号,它就可以通知其他线程继续。但我不推荐这样做,因为信号处理程序应该做尽可能小的功能。在信号处理程序中拥有复杂的功能通常被认为是不好的。您应该改为重新设计,以便其他线程不必停止(如果其他线程在记录调试信息时继续运行,会有什么问题?)。
1 处理这个问题的通常方法是使用专门的线程来处理信号。即阻止您感兴趣的信号并创建一个线程(在创建其他线程之前)来处理这些信号。 pthread_sigmask(3)
有一个如何操作的例子。
-
线程和信号的一些介绍(signal(7)
)
- 信号配置为per-process
信号处置是一个 per-process 属性:在多线程应用程序中,特定信号的处置对于所有线程都是相同的。
- 信号可能是process-directed或thread-directed
Process-directed 信号: process-directed 信号是针对(并因此等待)整个过程的信号。 process-directed 信号可以传递给当前未阻塞信号的任何一个线程。如果不止一个线程的信号被解除阻塞,那么内核会选择一个任意线程来传递信号。
Thread-directed 信号: thread-directed 信号是针对特定线程的信号。该集合将包含未决 process-directed 信号集和调用线程的未决信号集的并集。
- 异步和同步信号处理
您可以配置您的程序来告诉如何处理信号。你可以忽略它们(很少有不能忽略的),注册一个信号处理程序,当接收到特定信号时将调用它(asynchronous
),或者阻止它稍后处理它(synchronous
) .
针对您的情况,
"The question is: what happens to threads when signal handling function is running?"
信号被传送到配置为接收它的任何线程一次。异步处理信号的线程停止正在做的任何事情并跳转到配置的信号处理程序。其余线程中的执行流程不受影响。
If threads continue running their jobs, is there a way to freeze them while debugging handler is working?
没有执行此操作的标准方法。您需要建立自己的机制来启用此功能。
为了进一步研究,需要明确调试处理程序的执行位置。在每个线程或 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;
}
航站楼Session:
$ 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)