Gcc 线程 信号可以是进程导向的或线程导向的

Gcc 线程 信号可以是进程导向的或线程导向的,gcc,pthreads,signals,Gcc,Pthreads,Signals,过程导向信号:过程导向信号是针对整个过程(因此等待)的信号。进程定向的信号可以传送到当前未阻止该信号的任何一个线程。如果多个线程解除了信号阻塞,那么内核将选择一个任意线程向其发送信号 线程定向信号:线程定向信号是针对特定线程的信号。该集合将由挂起的进程定向信号集合和调用线程挂起的信号集合的并集组成 异步和同步信号处理 您可以将程序配置为告诉如何处理信号。您可以忽略它们(很少可以忽略),注册一个信号处理程序,该处理程序将在接收到特定信号时被调用(异步(/code>),或者阻止它以稍后处理(同步

过程导向信号:过程导向信号是针对整个过程(因此等待)的信号。进程定向的信号可以传送到当前未阻止该信号的任何一个线程。如果多个线程解除了信号阻塞,那么内核将选择一个任意线程向其发送信号

线程定向信号:线程定向信号是针对特定线程的信号。该集合将由挂起的进程定向信号集合和调用线程挂起的信号集合的并集组成

  • 异步和同步信号处理
您可以将程序配置为告诉如何处理信号。您可以忽略它们(很少可以忽略),注册一个信号处理程序,该处理程序将在接收到特定信号时被调用(
异步(/code>),或者阻止它以稍后处理(
同步(/code>)

说到你的案子

“问题是:当信号处理函数运行时,线程会发生什么情况?”

该信号只发送一次到配置为接收它的任何线程。异步处理信号的线程停止正在执行的任何操作,并跳转到已配置的信号处理程序。其余线程中的执行流不受影响

若线程继续运行它们的作业,在调试处理程序工作时是否有方法冻结它们

没有标准的方法可以做到这一点。您需要建立自己的机制来实现这一点

为了进一步研究,需要澄清调试处理程序的执行位置。在每个线程中或在
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;
}

处理程序在main()中注册如下
signal(SIGUSR1,info\u处理程序)@AntonZakharov在哪个线程中执行它并不重要。因为所有进程对于该特定信号将具有相同的信号配置。问题是您希望哪个线程执行该信号处理程序?主线程、每个线程或为调试信息注册的特定线程。正如我回答P.P时所说,我想在主线程中收集调试信息,因为它在等待连接的大部分时间是空闲的。调试信息对应于处理请求的正在运行的线程。据我所知,这个问题没有简单的解决办法。也许以另一种方式达到目标更好。@AntonZakharov不,你不需要改变你的实现想法。在一些项目中,可能需要这样的实施。接受挑战,找到周围的黑客。我编写了一个这样的黑客代码。在挑战中工作很有趣。谢谢:)非常感谢你花时间回答这个问题!处理程序在main()中注册如下
signal(SIGUSR1,info\u处理程序)@AntonZakharov在哪个线程中执行它并不重要。因为所有进程对于该特定信号将具有相同的信号配置。问题是您希望哪个线程执行该信号处理程序?主线程、每个线程或为调试信息注册的特定线程。正如我回答P.P时所说,我想在主线程中收集调试信息,因为它在等待连接的大部分时间是空闲的。调试信息对应于处理请求的正在运行的线程。据我所知,这个问题没有简单的解决办法。也许以另一种方式达到目标更好。@AntonZakharov不,你不需要改变你的实现想法。在一些项目中,可能需要这样的实施。接受挑战,找到周围的黑客。我编写了一个这样的黑客代码。在挑战中工作很有趣。谢谢:)非常感谢你花时间回答这个问题!这种奇怪要求的原因很简单:处理程序将有关运行线程的调试信息写入日志文件。在大多数情况下,线程的寿命很短。这种调试机制很可能不会投入生产。只有在开发阶段才有必要了解这个过程。您可以有一个专门的线程来处理SIGUSR1(在任何情况下都需要它-请参阅问题中的链接)。当SIGUSR1到达时,该线程将暂停(并取消暂停)所有其他线程,如中。通过这种方式,日志写入在信号处理程序上下文之外进行。此外,(1)在前一个信号的处理(即日志写入)完成之前,您需要决定当更多的SIGUSR1信号到达时要做什么。通常,您希望忽略进一步的SIGUSR1(2)当其他信号(例如SIGINT或SIGTERM)到达时应该做什么,这些信号可能具有不同的处理程序。(2) 如果您对它们感到困扰,那么这可能不是一个问题(例如,如果SIGTERM到达,您可能会让进程死亡-默认处置)。这种奇怪要求的原因很简单:处理程序将有关运行线程的调试信息写入日志文件。在大多数情况下,线程的寿命很短。这种调试机制很可能不会投入生产。只有在开发阶段才有必要了解这个过程。您可以有一个专门的线程来处理SIGUSR1(在任何情况下都需要它-请参阅问题中的链接)。当SIGUSR1到达时,该线程将暂停(并取消暂停)所有其他线程,如中。这样,日志写入在信号处理程序上下文之外进行
$ 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)